chore(plugin-workflow): add metric example (#3305)

* chore(plugin-workflow): add metric example

* refactor(plugin-workflow): refactor some code

* refactor(plugin-workflow): remove type for less dependencies
This commit is contained in:
Junyi 2024-01-03 09:59:33 +08:00 committed by GitHub
parent e8b7fbd699
commit cebd8efd2e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -39,8 +39,10 @@ export default class WorkflowPlugin extends Plugin {
private executing: Promise<void> | null = null; private executing: Promise<void> | null = null;
private pending: Pending[] = []; private pending: Pending[] = [];
private events: CachedEvent[] = []; private events: CachedEvent[] = [];
private eventsCount = 0;
private loggerCache: LRUCache<string, Logger>; private loggerCache: LRUCache<string, Logger>;
private meter = null;
getLogger(workflowId: ID): Logger { getLogger(workflowId: ID): Logger {
const now = new Date(); const now = new Date();
@ -165,6 +167,12 @@ export default class WorkflowPlugin extends Plugin {
}, },
}); });
this.meter = this.app.telemetry.metric.getMeter();
const counter = this.meter.createObservableGauge('workflow.events.counter');
counter.addCallback((result) => {
result.observe(this.eventsCount);
});
this.app.acl.registerSnippet({ this.app.acl.registerSnippet({
name: `pm.${this.name}.workflows`, name: `pm.${this.name}.workflows`,
actions: [ actions: [
@ -275,6 +283,7 @@ export default class WorkflowPlugin extends Plugin {
} }
this.events.push([workflow, context, options]); this.events.push([workflow, context, options]);
this.eventsCount = this.events.length;
logger.info(`new event triggered, now events: ${this.events.length}`); logger.info(`new event triggered, now events: ${this.events.length}`);
logger.debug(`event data:`, { logger.debug(`event data:`, {
@ -324,7 +333,7 @@ export default class WorkflowPlugin extends Plugin {
} }
} }
const execution = await this.db.sequelize.transaction(async (transaction) => { return this.db.sequelize.transaction(async (transaction) => {
const execution = await workflow.createExecution( const execution = await workflow.createExecution(
{ {
context, context,
@ -334,6 +343,8 @@ export default class WorkflowPlugin extends Plugin {
{ transaction }, { transaction },
); );
this.getLogger(workflow.id).info(`execution of workflow ${workflow.id} created as ${execution.id}`);
await workflow.increment(['executed', 'allExecuted'], { transaction }); await workflow.increment(['executed', 'allExecuted'], { transaction });
// NOTE: https://sequelize.org/api/v6/class/src/model.js~model#instance-method-increment // NOTE: https://sequelize.org/api/v6/class/src/model.js~model#instance-method-increment
if (this.db.options.dialect !== 'postgres') { if (this.db.options.dialect !== 'postgres') {
@ -356,19 +367,11 @@ export default class WorkflowPlugin extends Plugin {
return execution; return execution;
}); });
this.getLogger(workflow.id).info(`execution of workflow ${workflow.id} created as ${execution.id}`);
// NOTE: cache first execution for most cases
if (!this.executing && !this.pending.length) {
this.pending.push([execution]);
}
return execution;
} }
private prepare = async () => { private prepare = async () => {
const event = this.events.shift(); const event = this.events.shift();
this.eventsCount = this.events.length;
if (!event) { if (!event) {
this.getLogger('dispatcher').warn(`events queue is empty, no need to prepare`); this.getLogger('dispatcher').warn(`events queue is empty, no need to prepare`);
return; return;
@ -378,7 +381,11 @@ export default class WorkflowPlugin extends Plugin {
logger.info(`preparing execution for event`); logger.info(`preparing execution for event`);
try { try {
await this.createExecution(event); const execution = await this.createExecution(event);
// NOTE: cache first execution for most cases
if (!this.executing && !this.pending.length) {
this.pending.push([execution]);
}
} catch (err) { } catch (err) {
logger.error(`failed to create execution: ${err.message}`, err); logger.error(`failed to create execution: ${err.message}`, err);
// this.events.push(event); // NOTE: retry will cause infinite loop // this.events.push(event); // NOTE: retry will cause infinite loop