@codemation/host 0.9.0 → 0.9.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,27 @@
1
1
  # @codemation/host
2
2
 
3
+ ## 0.9.1
4
+
5
+ ### Patch Changes
6
+
7
+ - [#179](https://github.com/MadeRelevant/codemation/pull/179) [`6efde7a`](https://github.com/MadeRelevant/codemation/commit/6efde7aa045050cd2fbd22015f7608c513a6f79f) Thanks [@cblokland90](https://github.com/cblokland90)! - fix(hitl): gate the HITL timeout scheduler/worker on the scheduler abstraction instead of hardcoding Redis
8
+
9
+ `HitlTimeoutJobScheduler` and `HitlTimeoutWorker` previously fell back to
10
+ `redis://127.0.0.1:6379` unconditionally and always constructed a BullMQ
11
+ `Queue`/`Worker`. In inline/local mode (no Redis — e.g. managed workspace pods),
12
+ this caused two failures: the host crash-spammed `ECONNREFUSED 127.0.0.1:6379`,
13
+ and a HITL decision hung in `cancelTimeoutJob` (against the dead Redis) before the
14
+ run could resume, so the CP relay timed out (500) and the run never completed.
15
+
16
+ Both now gate on `appConfig.scheduler.kind` — the same abstraction the rest of the
17
+ host uses (`bullmq` only when a Redis URL is present, otherwise `local`). In local
18
+ mode they never touch Redis: `enqueueTimeoutJob`/`cancelTimeoutJob` are inert
19
+ no-ops and `start()` constructs no worker. Behavior is unchanged for Redis-backed
20
+ (`bullmq`) deployments.
21
+
22
+ Trade-off: in local mode, HITL expiry timeouts (auto-accept/halt on expiry) do not
23
+ fire, since there is no background queue. Manual decisions resume the run normally.
24
+
3
25
  ## 0.9.0
4
26
 
5
27
  ### Minor Changes
@@ -25932,14 +25932,15 @@ const HITL_TIMEOUT_QUEUE_NAME_SUFFIX = "hitl.timeout";
25932
25932
  let HitlTimeoutJobScheduler = class HitlTimeoutJobScheduler$1 {
25933
25933
  queue = null;
25934
25934
  queueName;
25935
+ /** Redis URL when running in BullMQ mode; null in local/inline mode (no Redis). */
25935
25936
  redisUrl;
25936
25937
  constructor(appConfig) {
25937
- const rawRedisUrl = appConfig.env.REDIS_URL ?? appConfig.env.CODEMATION_REDIS_URL;
25938
- this.redisUrl = rawRedisUrl && rawRedisUrl !== "" ? rawRedisUrl : "redis://127.0.0.1:6379";
25938
+ this.redisUrl = appConfig.scheduler.kind === "bullmq" ? appConfig.scheduler.redisUrl ?? null : null;
25939
25939
  this.queueName = `${appConfig.env.CODEMATION_BULLMQ_PREFIX ?? "codemation"}.${HITL_TIMEOUT_QUEUE_NAME_SUFFIX}`;
25940
25940
  }
25941
25941
  async enqueueTimeoutJob(args) {
25942
25942
  const queue = this.getOrCreateQueue();
25943
+ if (!queue) return;
25943
25944
  const delay = Math.max(0, args.expiresAt.getTime() - Date.now());
25944
25945
  await queue.add("hitl.timeout", {
25945
25946
  kind: "hitl.timeout",
@@ -25952,7 +25953,9 @@ let HitlTimeoutJobScheduler = class HitlTimeoutJobScheduler$1 {
25952
25953
  });
25953
25954
  }
25954
25955
  async cancelTimeoutJob(taskId) {
25955
- await (await this.getOrCreateQueue().getJob(this.makeJobId(taskId)))?.remove();
25956
+ const queue = this.getOrCreateQueue();
25957
+ if (!queue) return;
25958
+ await (await queue.getJob(this.makeJobId(taskId)))?.remove();
25956
25959
  }
25957
25960
  async close() {
25958
25961
  if (this.queue) {
@@ -25963,7 +25966,13 @@ let HitlTimeoutJobScheduler = class HitlTimeoutJobScheduler$1 {
25963
25966
  getQueueName() {
25964
25967
  return this.queueName;
25965
25968
  }
25969
+ /**
25970
+ * Returns the BullMQ queue in Redis-backed mode, or null in local/inline mode.
25971
+ * Construction is deferred to the first enqueue/cancel so DI consumers that
25972
+ * never enqueue can resolve this scheduler without building a connection.
25973
+ */
25966
25974
  getOrCreateQueue() {
25975
+ if (this.redisUrl === null) return null;
25967
25976
  if (!this.queue) {
25968
25977
  const connectionOptions = RedisConnectionOptionsFactory.fromConfig({ url: this.redisUrl });
25969
25978
  this.queue = new Queue(this.queueName, { connection: connectionOptions });
@@ -26018,6 +26027,7 @@ var _ref$8, _ref2$4, _ref3$1;
26018
26027
  let HitlTimeoutWorker = class HitlTimeoutWorker$1 {
26019
26028
  taskStore;
26020
26029
  worker = null;
26030
+ /** Redis connection options in BullMQ mode; null in local/inline mode (no Redis). */
26021
26031
  connectionOptions;
26022
26032
  constructor(taskStore, engine, scheduler, appConfig, resumeTelemetry) {
26023
26033
  this.engine = engine;
@@ -26025,10 +26035,11 @@ let HitlTimeoutWorker = class HitlTimeoutWorker$1 {
26025
26035
  this.resumeTelemetry = resumeTelemetry;
26026
26036
  if (!taskStore) throw new Error("HitlTimeoutWorker: HumanTaskStore is not registered.");
26027
26037
  this.taskStore = taskStore;
26028
- const redisUrl = appConfig.env.REDIS_URL ?? appConfig.env.CODEMATION_REDIS_URL ?? "redis://127.0.0.1:6379";
26029
- this.connectionOptions = RedisConnectionOptionsFactory.fromConfig({ url: redisUrl });
26038
+ const redisUrl = appConfig.scheduler.kind === "bullmq" ? appConfig.scheduler.redisUrl ?? null : null;
26039
+ this.connectionOptions = redisUrl === null ? null : RedisConnectionOptionsFactory.fromConfig({ url: redisUrl });
26030
26040
  }
26031
26041
  start() {
26042
+ if (!this.connectionOptions) return;
26032
26043
  this.worker = new Worker(this.scheduler.getQueueName(), async (job) => {
26033
26044
  await this.processJob(job);
26034
26045
  }, { connection: this.connectionOptions });
@@ -27180,4 +27191,4 @@ var AppContainerFactory = class AppContainerFactory {
27180
27191
 
27181
27192
  //#endregion
27182
27193
  export { WorkflowDefinitionMapper as A, CodemationHonoApiApp as C, FrontendAppConfigFactory as D, InternalAuthBootstrapFactory as E, StartWorkflowRunCommand as F, UpsertLocalBootstrapUserCommand as I, ListUserAccountsQuery as L, GetWorkflowDetailQuery as M, GetRunStateQuery as N, CodemationFrontendAuthSnapshotFactory as O, RunBinaryAttachmentLookupService as P, CredentialHttpRouteHandler as S, PublicFrontendBootstrapFactory as T, WorkflowHttpRouteHandler as _, GetCollectionQuery as a, RunHttpRouteHandler as b, InsertCollectionRowCommand as c, FrontendRuntime as d, CollectionSchemaSyncerHolder as f, ExecaProcessRunner as g, WorkflowRunRetentionPruneScheduler as h, GetCollectionRowQuery as i, GetWorkflowSummariesQuery as j, WorkflowWebsocketServer as k, DeleteCollectionRowCommand as l, AppContainerLifecycle as m, ListCollectionsQuery as n, UpdateCollectionRowCommand as o, DatabaseMigrations as p, ListCollectionRowsQuery as r, SyncCollectionsCommand as s, AppContainerFactory as t, WorkerRuntime as u, WebhookHttpRouteHandler as v, BinaryHttpRouteHandler as w, OAuth2HttpRouteHandler as x, RequestToWebhookItemMapper as y };
27183
- //# sourceMappingURL=AppContainerFactory-jpYXGZGe.js.map
27194
+ //# sourceMappingURL=AppContainerFactory-CHCXP2rn.js.map