Skip to content

Entity store/maintainer framework poc#253173

Merged
chennn1990 merged 38 commits intoelastic:mainfrom
chennn1990:entity-store/maintainer-framework-poc
Feb 19, 2026
Merged

Entity store/maintainer framework poc#253173
chennn1990 merged 38 commits intoelastic:mainfrom
chennn1990:entity-store/maintainer-framework-poc

Conversation

@chennn1990
Copy link
Copy Markdown
Contributor

@chennn1990 chennn1990 commented Feb 15, 2026

Summary

Adds a maintainer task framework to the entity_store plugin so other plugins can register custom recurring tasks that run in the context of the entity store (e.g. per-space maintenance). Registration is persisted in a new saved object; scheduling uses Task Manager and is triggered when an entity store is started (e.g. on install).

What's in scope

  • Public API: Plugin setup exposes registerEntityMaintainer(config) so consumers can register a maintainer with id, interval, run, optional setup, initialState, and description.
  • Persistence: A new hidden saved object type entity-maintainers-tasks stores the list of registered tasks (id + interval). A dedicated EntityMaintainersTasksClient owns all reads/writes so registration and scheduling stay free of direct SO usage.
  • Scheduling: When the entity store is started (e.g. via install API), all registered maintainer tasks are loaded from the client and scheduled with Task Manager (ensureScheduled) for the current space. Task runner supports optional first-run setup, status metadata (runs, lastSuccessTimestamp, lastErrorTimestamp), and debug logging.
  • Install flow: The install route now calls assetManager.init(req, entityTypes, logExtraction) so init and maintainer scheduling live in one place (with try/catch and error handling).

How to try it

  1. A sample maintainer is registered in plugin setup (id: entity-maintainer-task-test, interval: 20s) for POC.
  2. Call the install API with one or more entity types; after init, maintainer tasks for that space are scheduled.
  3. Check Task Manager and logs; task runner logs include task id and run number at debug level.

@chennn1990 chennn1990 requested a review from Copilot February 15, 2026 13:08
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces a maintainer task framework for the entity_store plugin, enabling other plugins to register custom recurring tasks that execute within the entity store context (e.g., per-space maintenance operations). The framework includes a public API for registration, persistence via saved objects, and Task Manager integration for scheduling.

Changes:

  • Added public API registerEntityMaintainer to plugin setup contract for task registration
  • Created EntityMaintainersTasksClient and saved object type for persistent task storage
  • Implemented task scheduling in scheduleEntityMaintainerTasks triggered during entity store initialization
  • Modified install flow to consolidate initialization and maintainer scheduling in AssetManager.init

Reviewed changes

Copilot reviewed 14 out of 15 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
types.ts Exports new setup contract with registerEntityMaintainer method
extract_entity_task.ts Added cleanup for test maintainer task on stop
entity_maintainer_task/types.ts Defines task configuration interface and status metadata types
entity_maintainer_task/index.ts Implements task registration, scheduling, and runner logic
constants.ts Added entityMaintainer to task type enum
config.ts Added configuration entry for maintainer tasks with optional interval
install.ts Simplified to call unified assetManager.init method
request_context_factory.ts Instantiates EntityMaintainersTasksClient for request context
plugin.ts Returns setup contract with registerEntityMaintainer and registers new saved object type
saved_objects/index.ts Exports maintainer tasks type and client
entity_maintainers_tasks_type.ts Defines saved object type for storing registered maintainer tasks
entity_maintainers_tasks_client.ts Client for CRUD operations on maintainer tasks saved object
constants.ts Added schema and type for maintainer task entries
asset_manager.ts Refactored to add init method that schedules maintainer tasks after entity initialization

@chennn1990 chennn1990 linked an issue Feb 15, 2026 that may be closed by this pull request
4 tasks
@chennn1990 chennn1990 marked this pull request as ready for review February 16, 2026 14:16
@chennn1990 chennn1990 requested a review from a team as a code owner February 16, 2026 14:16
@chennn1990 chennn1990 self-assigned this Feb 16, 2026
@chennn1990 chennn1990 added v9.4.0 release_note:skip Skip the PR/issue when compiling release notes backport:skip This PR does not require backporting labels Feb 16, 2026
@chennn1990 chennn1990 requested a review from hop-dev February 16, 2026 14:17
@chennn1990 chennn1990 linked an issue Feb 16, 2026 that may be closed by this pull request
4 tasks
EntityMaintainersTasksTypeName,
]);
const maintainerTasksClient = new EntityMaintainersTasksClient(internalRepo, logger);
maintainerTasksClient.addOrUpdate({ id, interval }).catch((err) => {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we await here?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not exactly, the id and interval are saved asynchronously to the saved object repository.
The maintainer task registration does not depend on that persistence step.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But then we don't have the guarantee that the promise has finished? Seems interesting to have it hanging

dynamic: false,
properties: {
'entity-maintainers-tasks': {
type: 'nested',
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of nested I think it would be simpler and more in line with other saved object types to have one document per maintainer

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@hop-dev do you have examples of how others behave?

Tbh, I wonder if we even need to have saved objects for this. Isn't this something that we have all in memory always? Why do we need to store in ES? If we have a kibana restart, the maintainer will be registered again, won't it?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah if you go to packages/kbn-check-saved-objects-cli/current_mappings.json which is part of this PRs diff we dump all of the saved object mappings in there. This would be the 11th use of nested in a saved object type in Kibana.

The other ones have lots of other properties on the object, whereas here we have one single property which is nested, which to me is like saying "these things are separate documents" because we have no shared maintainer properties.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@romulets The reason we are using saved object is because we need the id and interval for the scheduling phase.
This is the order:

  1. on setup phase - registering to the maintainers with all the configuration needed for it.
  2. on entity-store install phase - scheduling the maintainers, here we should get al the ids of the registered maintainers.

@hop-dev I will go over to figure out if there is a better option then nested

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

type: 'nested' – In Elasticsearch, an array of objects should be mapped as nested so each element is a single “document” and the pair id/interval stays together

@hop-dev that is exactly what i want

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My point is if that's what you want, and you have no other properties on this saved object, why not just have them as separate objects? I won't keep pushing the point, the core team will review too so they might give us some helpful guidance.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I want them to be together, because on install, when fetching all the registered id's, i need their related intervals.
If i will keep it separately i will lose the connection between maintainer id to its interval

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@romulets The reason we are using saved object is because we need the id and interval for the

Don't we have this in memory always?

Copy link
Copy Markdown
Member

@romulets romulets left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall looks good, two comments:

  1. Do we even need saved objects?
  2. I'd add a readme so we can point teams who use it on how to use and lifecycle of a maintainer (when it installs, when set up runs) and things like that

dynamic: false,
properties: {
'entity-maintainers-tasks': {
type: 'nested',
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@hop-dev do you have examples of how others behave?

Tbh, I wonder if we even need to have saved objects for this. Isn't this something that we have all in memory always? Why do we need to store in ES? If we have a kibana restart, the maintainer will be registered again, won't it?

const isFirstRun = currentStatus.metadata.runs === 0;
if (isFirstRun && setup) {
logger.debug(`First run, executing setup`);
currentStatus.state = await setup({
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a important lifecycle note - set up runs on first task run, and not in any kibana life cycle or first security page enter.

Personally, I think this setup could be hooked on the install process of entity store. But I'm fine with this decision if @hop-dev doesn't see any problem.

It's just something that needs to be documented

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that on install might be better for us. E.g risk scoring setup will create the risk scoring index. The UI queries this index so it seems nicer to have the logic "if the entity store is setup the risk score index will be there".

if all maintainers run straight away then maybe there isn't much difference between the approaches?

Copy link
Copy Markdown
Contributor Author

@chennn1990 chennn1990 Feb 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that on install might be better for us

@hop-dev @romulets This is effectively what will happen, once the installation is complete, all maintainers are scheduled, and their first execution will be triggered immediately (just not within the endpoint request thread).
I also see this as beneficial from a performance perspective, we don’t want to block the installation process while waiting for the initial execution of all maintainers to finish

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Feb 18, 2026

🔍 Preview links for changed docs

@elasticmachine
Copy link
Copy Markdown
Contributor

⏳ Build in-progress, with failures

Failed CI Steps

History

cc @chennn1990

@chennn1990 chennn1990 removed the request for review from a team February 19, 2026 09:48
@chennn1990 chennn1990 merged commit 590e1bc into elastic:main Feb 19, 2026
16 checks passed
ersin-erdal pushed a commit to ersin-erdal/kibana that referenced this pull request Feb 19, 2026
## Summary

Adds a **maintainer task framework** to the entity_store plugin so other
plugins can register custom recurring tasks that run in the context of
the entity store (e.g. per-space maintenance). Registration is persisted
in a new saved object; scheduling uses Task Manager and is triggered
when an entity store is started (e.g. on install).

## What's in scope

- **Public API:** Plugin setup exposes
`registerEntityMaintainer(config)` so consumers can register a
maintainer with `id`, `interval`, `run`, optional `setup`,
`initialState`, and `description`.
- **Persistence:** A new hidden saved object type
`entity-maintainers-tasks` stores the list of registered tasks (id +
interval). A dedicated **EntityMaintainersTasksClient** owns all
reads/writes so registration and scheduling stay free of direct SO
usage.
- **Scheduling:** When the entity store is started (e.g. via install
API), all registered maintainer tasks are loaded from the client and
scheduled with Task Manager (`ensureScheduled`) for the current space.
Task runner supports optional first-run `setup`, status metadata (runs,
lastSuccessTimestamp, lastErrorTimestamp), and debug logging.
- **Install flow:** The install route now calls `assetManager.init(req,
entityTypes, logExtraction)` so init and maintainer scheduling live in
one place (with try/catch and error handling).

## How to try it

1. A sample maintainer is registered in plugin setup (id:
`entity-maintainer-task-test`, interval: `20s`) for POC.
2. Call the install API with one or more entity types; after init,
maintainer tasks for that space are scheduled.
3. Check Task Manager and logs; task runner logs include task id and run
number at debug level.

---------

Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backport:skip This PR does not require backporting release_note:skip Skip the PR/issue when compiling release notes v9.4.0

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Create a POC of the entity maintainers framework

7 participants