patchrelay 0.8.0 → 0.8.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.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "service": "patchrelay",
3
- "version": "0.8.0",
4
- "commit": "c4fcada0fce7",
5
- "builtAt": "2026-03-18T10:29:36.175Z"
3
+ "version": "0.8.1",
4
+ "commit": "362440acad55",
5
+ "builtAt": "2026-03-18T10:38:01.072Z"
6
6
  }
@@ -1,5 +1,6 @@
1
1
  import { SerialWorkQueue } from "./service-queue.js";
2
2
  const ISSUE_KEY_DELIMITER = "::";
3
+ const DEFAULT_RECONCILE_INTERVAL_MS = 5_000;
3
4
  function toReconciler(value) {
4
5
  if (typeof value === "function") {
5
6
  return {
@@ -40,13 +41,17 @@ function makeIssueQueueKey(item) {
40
41
  export class ServiceRuntime {
41
42
  codex;
42
43
  logger;
44
+ options;
43
45
  webhookQueue;
44
46
  issueQueue;
45
47
  ready = false;
46
48
  startupError;
47
- constructor(codex, logger, stageRunReconciler, readyIssueSource, webhookProcessor, issueProcessor) {
49
+ reconcileTimer;
50
+ reconcileInProgress = false;
51
+ constructor(codex, logger, stageRunReconciler, readyIssueSource, webhookProcessor, issueProcessor, options = {}) {
48
52
  this.codex = codex;
49
53
  this.logger = logger;
54
+ this.options = options;
50
55
  this.stageRunReconciler = toReconciler(stageRunReconciler);
51
56
  this.readyIssueSource = toReadyIssueSource(readyIssueSource);
52
57
  this.webhookProcessor = toWebhookProcessor(webhookProcessor);
@@ -69,6 +74,7 @@ export class ServiceRuntime {
69
74
  }
70
75
  this.ready = true;
71
76
  this.startupError = undefined;
77
+ this.scheduleBackgroundReconcile();
72
78
  }
73
79
  catch (error) {
74
80
  this.ready = false;
@@ -78,6 +84,7 @@ export class ServiceRuntime {
78
84
  }
79
85
  stop() {
80
86
  this.ready = false;
87
+ this.clearBackgroundReconcile();
81
88
  void this.codex.stop();
82
89
  }
83
90
  enqueueWebhookEvent(eventId, options) {
@@ -93,4 +100,42 @@ export class ServiceRuntime {
93
100
  ...(this.startupError ? { startupError: this.startupError } : {}),
94
101
  };
95
102
  }
103
+ scheduleBackgroundReconcile() {
104
+ this.clearBackgroundReconcile();
105
+ const timer = setTimeout(() => {
106
+ void this.runBackgroundReconcile();
107
+ }, this.options.reconcileIntervalMs ?? DEFAULT_RECONCILE_INTERVAL_MS);
108
+ timer.unref?.();
109
+ this.reconcileTimer = timer;
110
+ }
111
+ clearBackgroundReconcile() {
112
+ if (this.reconcileTimer !== undefined) {
113
+ clearTimeout(this.reconcileTimer);
114
+ this.reconcileTimer = undefined;
115
+ }
116
+ }
117
+ async runBackgroundReconcile() {
118
+ if (!this.ready || !this.codex.isStarted()) {
119
+ return;
120
+ }
121
+ if (this.reconcileInProgress) {
122
+ this.scheduleBackgroundReconcile();
123
+ return;
124
+ }
125
+ this.reconcileInProgress = true;
126
+ try {
127
+ await this.stageRunReconciler.reconcileActiveStageRuns();
128
+ }
129
+ catch (error) {
130
+ this.logger.warn({
131
+ error: error instanceof Error ? error.message : String(error),
132
+ }, "Background active-stage reconciliation failed");
133
+ }
134
+ finally {
135
+ this.reconcileInProgress = false;
136
+ if (this.ready) {
137
+ this.scheduleBackgroundReconcile();
138
+ }
139
+ }
140
+ }
96
141
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "patchrelay",
3
- "version": "0.8.0",
3
+ "version": "0.8.1",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "repository": {