@hotmeshio/hotmesh
Version:
Permanent-Memory Workflows & AI Agents
159 lines (158 loc) • 6.57 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Interrupt = void 0;
const errors_1 = require("../../modules/errors");
const collator_1 = require("../collator");
const pipe_1 = require("../pipe");
const telemetry_1 = require("../telemetry");
const activity_1 = require("./activity");
class Interrupt extends activity_1.Activity {
constructor(config, data, metadata, hook, engine, context) {
super(config, data, metadata, hook, engine, context);
}
//******** LEG 1 ENTRY ********//
async process() {
this.logger.debug('interrupt-process', {
jid: this.context.metadata.jid,
gid: this.context.metadata.gid,
aid: this.metadata.aid,
});
let telemetry;
try {
await this.verifyEntry();
telemetry = new telemetry_1.TelemetryService(this.engine.appId, this.config, this.metadata, this.context);
telemetry.startActivitySpan(this.leg);
if (this.isInterruptingSelf()) {
await this.interruptSelf(telemetry);
}
else {
await this.interruptAnother(telemetry);
}
}
catch (error) {
if (error instanceof errors_1.InactiveJobError) {
this.logger.error('interrupt-inactive-job-error', { error });
return;
}
else if (error instanceof errors_1.GenerationalError) {
this.logger.info('process-event-generational-job-error', { error });
return;
}
else if (error instanceof errors_1.GetStateError) {
this.logger.error('interrupt-get-state-error', { error });
return;
}
else if (error instanceof errors_1.CollationError) {
if (error.fault === 'duplicate') {
this.logger.info('interrupt-collation-overage', {
job_id: this.context.metadata.jid,
guid: this.context.metadata.guid,
});
return;
}
//unknown collation error
this.logger.error('interrupt-collation-error', { error });
}
else {
this.logger.error('interrupt-process-error', { error });
}
telemetry?.setActivityError(error.message);
throw error;
}
finally {
telemetry?.endActivitySpan();
this.logger.debug('interrupt-process-end', {
jid: this.context.metadata.jid,
gid: this.context.metadata.gid,
aid: this.metadata.aid,
});
}
}
async interruptSelf(telemetry) {
// Apply final updates to THIS job's state
if (this.config.job?.maps) {
this.mapJobData();
await this.setState();
}
// Interrupt THIS job
const messageId = await this.interrupt();
// Notarize completion and log
telemetry.mapActivityAttributes();
const transaction = this.store.transact();
await collator_1.CollatorService.notarizeEarlyCompletion(this, transaction);
await this.setStatus(-1, transaction);
const txResponse = (await transaction.exec());
const jobStatus = this.resolveStatus(txResponse);
telemetry.setActivityAttributes({
'app.activity.mid': messageId,
'app.job.jss': jobStatus,
});
return this.context.metadata.aid;
}
async interruptAnother(telemetry) {
// Interrupt ANOTHER job
const messageId = await this.interrupt();
const attrs = { 'app.activity.mid': messageId };
// Apply updates to THIS job's state
telemetry.mapActivityAttributes();
this.adjacencyList = await this.filterAdjacent();
if (this.config.job?.maps || this.config.output?.maps) {
this.mapOutputData();
this.mapJobData();
const transaction = this.store.transact();
await this.setState(transaction);
}
// Notarize completion
const transaction = this.store.transact();
await collator_1.CollatorService.notarizeEarlyCompletion(this, transaction);
await this.setStatus(this.adjacencyList.length - 1, transaction);
const txResponse = (await transaction.exec());
const jobStatus = this.resolveStatus(txResponse);
attrs['app.job.jss'] = jobStatus;
// Transition next generation and log
const messageIds = await this.transition(this.adjacencyList, jobStatus);
if (messageIds.length) {
attrs['app.activity.mids'] = messageIds.join(',');
}
telemetry.setActivityAttributes(attrs);
return this.context.metadata.aid;
}
isInterruptingSelf() {
if (!this.config.target) {
return true;
}
const resolvedJob = pipe_1.Pipe.resolve(this.config.target, this.context);
return resolvedJob == this.context.metadata.jid;
}
resolveInterruptOptions() {
return {
reason: this.config.reason !== undefined
? pipe_1.Pipe.resolve(this.config.reason, this.context)
: undefined,
throw: this.config.throw !== undefined
? pipe_1.Pipe.resolve(this.config.throw, this.context)
: undefined,
descend: this.config.descend !== undefined
? pipe_1.Pipe.resolve(this.config.descend, this.context)
: undefined,
code: this.config.code !== undefined
? pipe_1.Pipe.resolve(this.config.code, this.context)
: undefined,
expire: this.config.expire !== undefined
? pipe_1.Pipe.resolve(this.config.expire, this.context)
: undefined,
stack: this.config.stack !== undefined
? pipe_1.Pipe.resolve(this.config.stack, this.context)
: undefined,
};
}
async interrupt() {
const options = this.resolveInterruptOptions();
return await this.engine.interrupt(this.config.topic !== undefined
? pipe_1.Pipe.resolve(this.config.topic, this.context)
: this.context.metadata.tpc, this.config.target !== undefined
? pipe_1.Pipe.resolve(this.config.target, this.context)
: this.context.metadata.jid, options);
}
}
exports.Interrupt = Interrupt;