gencow 0.1.103 → 0.1.104
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/bin/gencow.mjs +4 -2
- package/core/index.js +6 -1
- package/package.json +1 -1
- package/server/index.js +72 -31
- package/server/index.js.map +2 -2
package/bin/gencow.mjs
CHANGED
|
@@ -2148,6 +2148,7 @@ ${BOLD}Examples:${RESET}
|
|
|
2148
2148
|
method: "POST",
|
|
2149
2149
|
headers: {
|
|
2150
2150
|
"Content-Type": "application/octet-stream",
|
|
2151
|
+
"X-Deploy-Local-Dir": process.cwd(),
|
|
2151
2152
|
},
|
|
2152
2153
|
body: bundleBuffer,
|
|
2153
2154
|
});
|
|
@@ -2202,6 +2203,7 @@ ${BOLD}Examples:${RESET}
|
|
|
2202
2203
|
method: "POST",
|
|
2203
2204
|
headers: {
|
|
2204
2205
|
"Content-Type": "application/octet-stream",
|
|
2206
|
+
"X-Deploy-Local-Dir": process.cwd(),
|
|
2205
2207
|
},
|
|
2206
2208
|
body: retryBuffer,
|
|
2207
2209
|
});
|
|
@@ -2610,7 +2612,7 @@ ${BOLD}Examples:${RESET}
|
|
|
2610
2612
|
|
|
2611
2613
|
const backendDeployRes = await platformFetch(creds, `/platform/apps/${appId}/deploy?env=${envTarget}`, {
|
|
2612
2614
|
method: "POST",
|
|
2613
|
-
headers: { "Content-Type": "application/octet-stream" },
|
|
2615
|
+
headers: { "Content-Type": "application/octet-stream", "X-Deploy-Local-Dir": process.cwd() },
|
|
2614
2616
|
body: backendBuffer,
|
|
2615
2617
|
});
|
|
2616
2618
|
|
|
@@ -2693,7 +2695,7 @@ ${BOLD}Examples:${RESET}
|
|
|
2693
2695
|
|
|
2694
2696
|
const deployRes = await platformFetch(creds, `/platform/apps/${appId}/deploy-static`, {
|
|
2695
2697
|
method: "POST",
|
|
2696
|
-
headers: { "Content-Type": "application/octet-stream" },
|
|
2698
|
+
headers: { "Content-Type": "application/octet-stream", "X-Deploy-Local-Dir": process.cwd() },
|
|
2697
2699
|
body: bundleBuffer,
|
|
2698
2700
|
});
|
|
2699
2701
|
|
package/core/index.js
CHANGED
|
@@ -1665,7 +1665,12 @@ function createScheduler() {
|
|
|
1665
1665
|
actions.set(name, handler);
|
|
1666
1666
|
},
|
|
1667
1667
|
async executeAction(name, args) {
|
|
1668
|
-
|
|
1668
|
+
try {
|
|
1669
|
+
await executeAction(name, args);
|
|
1670
|
+
} catch (error) {
|
|
1671
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
1672
|
+
console.error(`[scheduler] executeAction("${name}") failed: ${msg}`);
|
|
1673
|
+
}
|
|
1669
1674
|
}
|
|
1670
1675
|
};
|
|
1671
1676
|
}
|
package/package.json
CHANGED
package/server/index.js
CHANGED
|
@@ -1673,7 +1673,12 @@ function createScheduler() {
|
|
|
1673
1673
|
actions.set(name21, handler);
|
|
1674
1674
|
},
|
|
1675
1675
|
async executeAction(name21, args) {
|
|
1676
|
-
|
|
1676
|
+
try {
|
|
1677
|
+
await executeAction(name21, args);
|
|
1678
|
+
} catch (error95) {
|
|
1679
|
+
const msg = error95 instanceof Error ? error95.message : String(error95);
|
|
1680
|
+
console.error(`[scheduler] executeAction("${name21}") failed: ${msg}`);
|
|
1681
|
+
}
|
|
1677
1682
|
}
|
|
1678
1683
|
};
|
|
1679
1684
|
}
|
|
@@ -82259,10 +82264,6 @@ if (IS_BAAS) {
|
|
|
82259
82264
|
const contentLength = c.res.headers.get("content-length");
|
|
82260
82265
|
if (contentLength) {
|
|
82261
82266
|
runtimeBuffer.add("bandwidth_bytes", parseInt(contentLength, 10));
|
|
82262
|
-
} else if (c.res.body) {
|
|
82263
|
-
const cloned = c.res.clone();
|
|
82264
|
-
const buf = await cloned.arrayBuffer();
|
|
82265
|
-
runtimeBuffer.add("bandwidth_bytes", buf.byteLength);
|
|
82266
82267
|
}
|
|
82267
82268
|
} catch {
|
|
82268
82269
|
}
|
|
@@ -82637,25 +82638,19 @@ async function main() {
|
|
|
82637
82638
|
// @ts-ignore
|
|
82638
82639
|
duplex: "half"
|
|
82639
82640
|
});
|
|
82641
|
+
const buf = await proxyRes.arrayBuffer();
|
|
82640
82642
|
if (appName) {
|
|
82641
|
-
|
|
82642
|
-
const cl = proxyRes.headers.get("content-length");
|
|
82643
|
-
if (cl) {
|
|
82644
|
-
addProxyMetric(appName, parseInt(cl, 10));
|
|
82645
|
-
} else if (proxyRes.body) {
|
|
82646
|
-
const buf = await proxyRes.arrayBuffer();
|
|
82647
|
-
addProxyMetric(appName, buf.byteLength);
|
|
82648
|
-
return new Response(buf, {
|
|
82649
|
-
status: proxyRes.status,
|
|
82650
|
-
headers: proxyRes.headers
|
|
82651
|
-
});
|
|
82652
|
-
}
|
|
82653
|
-
} catch {
|
|
82654
|
-
}
|
|
82643
|
+
addProxyMetric(appName, buf.byteLength);
|
|
82655
82644
|
}
|
|
82656
|
-
|
|
82645
|
+
const resHeaders = new Headers(proxyRes.headers);
|
|
82646
|
+
if (buf.byteLength > 0) {
|
|
82647
|
+
resHeaders.set("content-length", String(buf.byteLength));
|
|
82648
|
+
} else {
|
|
82649
|
+
resHeaders.delete("content-length");
|
|
82650
|
+
}
|
|
82651
|
+
return new Response(buf, {
|
|
82657
82652
|
status: proxyRes.status,
|
|
82658
|
-
headers:
|
|
82653
|
+
headers: resHeaders
|
|
82659
82654
|
});
|
|
82660
82655
|
}
|
|
82661
82656
|
async function serveStaticFile(c, dataDir, pathname, appName) {
|
|
@@ -82771,6 +82766,22 @@ async function main() {
|
|
|
82771
82766
|
if (sleepingApps.length > 0) {
|
|
82772
82767
|
console.log(`[platform] Registered ${sleepingApps.length} sleeping app(s) into memory for future wake \u2713`);
|
|
82773
82768
|
}
|
|
82769
|
+
const allAppsForCronSync = [...runningApps, ...sleepingApps];
|
|
82770
|
+
if (allAppsForCronSync.length > 0) {
|
|
82771
|
+
const { syncCronJobs: _syncCronJobs } = await import(resolve5(functionsPath, "../src/provisioner.ts"));
|
|
82772
|
+
let cronSyncCount = 0;
|
|
82773
|
+
for (const row of allAppsForCronSync) {
|
|
82774
|
+
try {
|
|
82775
|
+
await _syncCronJobs(row.id, row.name, row.dataDir);
|
|
82776
|
+
cronSyncCount++;
|
|
82777
|
+
} catch (e) {
|
|
82778
|
+
console.warn(`[cron] ${row.name}: boot-time cron sync failed:`, e.message);
|
|
82779
|
+
}
|
|
82780
|
+
}
|
|
82781
|
+
if (cronSyncCount > 0) {
|
|
82782
|
+
console.log(`[platform] Boot-time cron sync complete for ${cronSyncCount}/${allAppsForCronSync.length} app(s) \u2713`);
|
|
82783
|
+
}
|
|
82784
|
+
}
|
|
82774
82785
|
} catch (e) {
|
|
82775
82786
|
const msg = e instanceof Error ? e.message : String(e);
|
|
82776
82787
|
console.error("[platform] Auto-recovery failed:", msg);
|
|
@@ -82808,15 +82819,27 @@ async function main() {
|
|
|
82808
82819
|
try {
|
|
82809
82820
|
const { canSleep: _canSleep, sleepApp: _sleepApp, getLastAccess: _getLastAccess, getAppMeta: _getAppMeta } = await import(resolve5(functionsPath, "../src/provisioner.ts"));
|
|
82810
82821
|
const metaMap = _getAppMeta();
|
|
82822
|
+
const allApps = await db.select({ name: appsTable.name, status: appsTable.status }).from(appsTable);
|
|
82823
|
+
const dbStatusMap = new Map(allApps.map((a) => [a.name, a.status]));
|
|
82811
82824
|
for (const [appName] of metaMap) {
|
|
82812
82825
|
if (sleepCount >= MAX_SLEEP_PER_CYCLE) break;
|
|
82826
|
+
const dbStatus = dbStatusMap.get(appName);
|
|
82827
|
+
if (dbStatus === "sleeping") {
|
|
82828
|
+
console.log(`[sleep] SWEEP: ${appName} is "sleeping" in DB but active in memory \u2014 enforcing sleep...`);
|
|
82829
|
+
try {
|
|
82830
|
+
await _sleepApp(appName);
|
|
82831
|
+
sleepCount++;
|
|
82832
|
+
} catch (e) {
|
|
82833
|
+
console.error(`[sleep] Failed to sweep ghost app ${appName}:`, e);
|
|
82834
|
+
}
|
|
82835
|
+
continue;
|
|
82836
|
+
}
|
|
82813
82837
|
const last = _getLastAccess(appName) || 0;
|
|
82814
82838
|
const canSlp = _canSleep(appName);
|
|
82815
82839
|
if (!canSlp) continue;
|
|
82816
82840
|
const idleMin = Math.floor((Date.now() - last) / 6e4);
|
|
82817
82841
|
try {
|
|
82818
82842
|
await _sleepApp(appName);
|
|
82819
|
-
await db.update(appsTable).set({ status: "sleeping" }).where(eqOp(appsTable.name, appName));
|
|
82820
82843
|
console.log(`[sleep] ${appName}: idle ${idleMin}m \u2014 sleeping \u2713`);
|
|
82821
82844
|
sleepCount++;
|
|
82822
82845
|
} catch (e) {
|
|
@@ -82909,6 +82932,8 @@ async function main() {
|
|
|
82909
82932
|
console.error(`[cron] ${label}: failed (${elapsed}s) \u2014 ${errMsg}`);
|
|
82910
82933
|
}
|
|
82911
82934
|
}
|
|
82935
|
+
let _cronEmptyCount = 0;
|
|
82936
|
+
const CRON_EMPTY_LOG_INTERVAL = 5;
|
|
82912
82937
|
setInterval(async () => {
|
|
82913
82938
|
try {
|
|
82914
82939
|
const dueJobs = await rawSql(
|
|
@@ -82921,15 +82946,31 @@ async function main() {
|
|
|
82921
82946
|
ORDER BY cj.next_run_at ASC
|
|
82922
82947
|
LIMIT 50`
|
|
82923
82948
|
);
|
|
82924
|
-
if (dueJobs.length === 0)
|
|
82925
|
-
|
|
82926
|
-
|
|
82927
|
-
|
|
82928
|
-
await Promise.allSettled(batch.map((job) => executeCronJob(job)));
|
|
82929
|
-
if (i + CRON_CONCURRENCY < dueJobs.length) {
|
|
82930
|
-
await new Promise((r) => setTimeout(r, 1e3));
|
|
82949
|
+
if (dueJobs.length === 0) {
|
|
82950
|
+
_cronEmptyCount++;
|
|
82951
|
+
if (_cronEmptyCount % CRON_EMPTY_LOG_INTERVAL === 0) {
|
|
82952
|
+
console.log(`[cron] No due jobs (${_cronEmptyCount} consecutive empty polls)`);
|
|
82931
82953
|
}
|
|
82954
|
+
return;
|
|
82932
82955
|
}
|
|
82956
|
+
_cronEmptyCount = 0;
|
|
82957
|
+
console.log(`[cron] ${dueJobs.length} due cron job(s) found`);
|
|
82958
|
+
for (const job of dueJobs) {
|
|
82959
|
+
const nextRun = cronCalculateNextRun2(job.schedule);
|
|
82960
|
+
await rawSql(
|
|
82961
|
+
`UPDATE cron_jobs SET next_run_at = $1 WHERE id = $2`,
|
|
82962
|
+
[nextRun, job.id]
|
|
82963
|
+
);
|
|
82964
|
+
}
|
|
82965
|
+
void (async () => {
|
|
82966
|
+
for (let i = 0; i < dueJobs.length; i += CRON_CONCURRENCY) {
|
|
82967
|
+
const batch = dueJobs.slice(i, i + CRON_CONCURRENCY);
|
|
82968
|
+
await Promise.allSettled(batch.map((job) => executeCronJob(job)));
|
|
82969
|
+
if (i + CRON_CONCURRENCY < dueJobs.length) {
|
|
82970
|
+
await new Promise((r) => setTimeout(r, 1e3));
|
|
82971
|
+
}
|
|
82972
|
+
}
|
|
82973
|
+
})();
|
|
82933
82974
|
} catch (err) {
|
|
82934
82975
|
console.error(`[cron] Scheduler error:`, err.message);
|
|
82935
82976
|
}
|
|
@@ -83253,7 +83294,7 @@ async function main() {
|
|
|
83253
83294
|
if (!IS_BAAS && Array.isArray(result) && result.length >= 2) {
|
|
83254
83295
|
checkMixedUserIds(name21, result);
|
|
83255
83296
|
}
|
|
83256
|
-
return c.json(result);
|
|
83297
|
+
return c.json(result ?? null);
|
|
83257
83298
|
} catch (err) {
|
|
83258
83299
|
const status = err?.code === "FUNCTION_TIMEOUT" ? 408 : err instanceof GencowValidationError ? 400 : 500;
|
|
83259
83300
|
return c.json({ error: err.message, ...err?.code ? { code: err.code } : {} }, status);
|
|
@@ -83288,7 +83329,7 @@ async function main() {
|
|
|
83288
83329
|
name21
|
|
83289
83330
|
);
|
|
83290
83331
|
await invalidateQueries(mut.invalidates, ctx);
|
|
83291
|
-
return c.json(result, 201);
|
|
83332
|
+
return c.json(result ?? null, 201);
|
|
83292
83333
|
} catch (err) {
|
|
83293
83334
|
const status = err?.code === "FUNCTION_TIMEOUT" ? 408 : err instanceof GencowValidationError ? 400 : 500;
|
|
83294
83335
|
return c.json({ error: err.message, ...err?.code ? { code: err.code } : {} }, status);
|