Skip to content

Plugin Support + New Statistic Plugins#58

Closed
darrenpicard25 wants to merge 15 commits intomasterfrom
statistics-monitoring
Closed

Plugin Support + New Statistic Plugins#58
darrenpicard25 wants to merge 15 commits intomasterfrom
statistics-monitoring

Conversation

@darrenpicard25
Copy link
Collaborator

@darrenpicard25 darrenpicard25 commented Jan 21, 2026

Added new statisticsCollected and statisticsCollectedError events to processors as well as new configuration option. Added new statistics method to datastore

This work is to allow better monitoring capabilities to chrono.

Changes are considered breaking due to the forced change on the Datastore interface. As we are still pre 1.0 release I am okay forcing changes

Additional Things:

  • Improved some documentation
  • added more tests
  • updated dev dependencies
  • set up lint-staged
  • improved CI pipeline

@wiz-a38520980d
Copy link

wiz-a38520980d bot commented Jan 21, 2026

Wiz Scan Summary

Scanner Findings
Vulnerability Finding Vulnerabilities 5 Medium 2 Low
Data Finding Sensitive Data -
Secret Finding Secrets -
IaC Misconfiguration IaC Misconfigurations -
SAST Finding SAST Findings -
Total 5 Medium 2 Low

View scan details in Wiz

To detect these findings earlier in the dev lifecycle, try using Wiz Code VS Code Extension.

"types": "./build/index.d.ts",
"default": "./build/index.js"
"types": "./build/index.d.cts",
"default": "./build/index.cjs"
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

something i missed from my previous update supporting esm and commonjs

@darrenpicard25 darrenpicard25 marked this pull request as ready for review January 21, 2026 04:14
tjamescouch
tjamescouch previously approved these changes Jan 21, 2026
return task ? this.toObject(task) : undefined;
}

public async statistics<TaskKind extends Extract<keyof TaskMapping, string>>(
Copy link
Collaborator

Choose a reason for hiding this comment

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

Seems a little odd to have a function not named using a verb. Any reason not to name it getStatistics?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

agree it is weird. i originally had getStatistics but it also kinda looked wrong next to claim, delete, retry, schedule, etc

but maybe that is just me. let me know your preference

Copy link
Collaborator

Choose a reason for hiding this comment

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

TBH I grew to like it by the end of reading. Im ok either way, the brevity is nice even if it does not meet style guides :)

Copy link
Collaborator

Choose a reason for hiding this comment

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

The statistics method may seem fine. Another option we can use here is collectStatistics(...). What do you think?

Comment on lines +219 to +237
const [claimableTaskCount, failedTaskCount] = await Promise.all([
collection.countDocuments({
kind: input.taskKind,
scheduledAt: { $lte: now },
$or: [
{ status: TaskStatus.PENDING },
{
status: TaskStatus.CLAIMED,
claimedAt: {
$lte: new Date(now.getTime() - input.claimStaleTimeoutMs),
},
},
],
}),
collection.countDocuments({
kind: input.taskKind,
status: TaskStatus.FAILED,
}),
]);
Copy link
Member

Choose a reason for hiding this comment

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

It would be amazing to also get stats for scheduled tasks, no?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

not sure im following you here.

Copy link
Collaborator

@maiahneo maiahneo left a comment

Choose a reason for hiding this comment

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

Looks fine. But I'm thinking of doing the Statistics outside of SimpleProcessor. The SimpleProcessor should be just about processing the tasks and it's lifecycle.

Maybe we can have a design like:

class Chrono {
  // Other exiting methods  here...

  //  This is an existing method
  public registerTaskHandler() {
    const processor = createProcessor({...});
    const statsCollector = createStatsCollector({ processor });

    // then we can return the collector here as well and the
    // user can listen from its events
    return { processor, statsCollector } 
}

Or another approach is to put the StatsCollector outside Chrono so we can do

const chrono = new Chrono();
const statsCollector = new StatsCollector({ chrono });

// then maybe we can start it...
statsCollector.start()

// then listen to its events for example...
statsCollector.on('stats-collected', () => { ... });
statsCollector.on('stats-collection-error', () => { ... });

Obviously those are just pseudo(s) but the idea is to de-couple the Stats collector from the Task Processor in hope to make those 2 distinct processes simpler, easier to maintain, and debug in the future. Let me know your thoughts! 😉

Comment on lines -32 to -33

ProcessorEvents.TASK_CLAIMED;
Copy link
Collaborator

Choose a reason for hiding this comment

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

😅

Copy link
Collaborator

@maiahneo maiahneo left a comment

Choose a reason for hiding this comment

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

Agree on James' concern on the naming of the method below. I have a suggestion but non-blocking since it's an internal method (for data-stores to implement) and we can change in the future.

return task ? this.toObject(task) : undefined;
}

public async statistics<TaskKind extends Extract<keyof TaskMapping, string>>(
Copy link
Collaborator

Choose a reason for hiding this comment

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

The statistics method may seem fine. Another option we can use here is collectStatistics(...). What do you think?

@darrenpicard25
Copy link
Collaborator Author

Looks fine. But I'm thinking of doing the Statistics outside of SimpleProcessor. The SimpleProcessor should be just about processing the tasks and it's lifecycle.

Maybe we can have a design like:

class Chrono {
  // Other exiting methods  here...

  //  This is an existing method
  public registerTaskHandler() {
    const processor = createProcessor({...});
    const statsCollector = createStatsCollector({ processor });

    // then we can return the collector here as well and the
    // user can listen from its events
    return { processor, statsCollector } 
}

Or another approach is to put the StatsCollector outside Chrono so we can do

const chrono = new Chrono();
const statsCollector = new StatsCollector({ chrono });

// then maybe we can start it...
statsCollector.start()

// then listen to its events for example...
statsCollector.on('stats-collected', () => { ... });
statsCollector.on('stats-collection-error', () => { ... });

Obviously those are just pseudo(s) but the idea is to de-couple the Stats collector from the Task Processor in hope to make those 2 distinct processes simpler, easier to maintain, and debug in the future. Let me know your thoughts! 😉

damn..... that stat collector is a pretty good idea

@darrenpicard25 darrenpicard25 changed the title Added new statistics events and handlers Plugin Support + New Statistic Plugins Jan 30, 2026
Copy link
Collaborator

@maiahneo maiahneo left a comment

Choose a reason for hiding this comment

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

Great work on this Darren! I like the Plugins idea 😃

There's a lot of things going on in this PR. To review it properly do you it can be break down to parts like below?

PR 1: Code gardening, docs update, config updates, npm deps updates.
PR 2: Chrono plugin support.
PR 3: Statistics collector.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Thanks for adding this Darren! ❤️

* @param plugin - The plugin to register
* @returns The plugin's API (if any) for type-safe access to plugin functionality
*/
use<API>(plugin: ChronoPlugin<TaskMapping, API>): API {
Copy link
Collaborator

@maiahneo maiahneo Jan 30, 2026

Choose a reason for hiding this comment

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

I like the chrono.use(myPlugin) syntax! It feels convenient and lightweight like how express/hono middleware does.

💅 Just to make it straight forward (API seems vague when I read it, and I need to read the jsdoc to understand what it represents)

Suggested change
use<API>(plugin: ChronoPlugin<TaskMapping, API>): API {
use<PluginAPI>(plugin: ChronoPlugin<TaskMapping, PluginAPI>): PluginAPI {

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants