@pikku/core 0.12.42 → 0.12.45
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 +39 -0
- package/dist/index.d.ts +1 -1
- package/dist/middleware/auth-apikey.d.ts +1 -0
- package/dist/middleware/auth-bearer.d.ts +1 -0
- package/dist/middleware/auth-cookie.d.ts +1 -0
- package/dist/middleware/cors.d.ts +1 -0
- package/dist/middleware/remote-auth.d.ts +1 -0
- package/dist/middleware/telemetry.d.ts +2 -0
- package/dist/middleware/timeout.d.ts +1 -0
- package/dist/types/core.types.d.ts +32 -0
- package/dist/wirings/ai-agent/voice-input.d.ts +1 -0
- package/dist/wirings/ai-agent/voice-output.d.ts +1 -0
- package/dist/wirings/rpc/rpc-runner.d.ts +1 -0
- package/dist/wirings/workflow/pikku-workflow-service.js +97 -91
- package/package.json +3 -3
- package/src/index.ts +1 -0
- package/src/types/core.types.ts +33 -0
- package/src/wirings/workflow/pikku-workflow-service.ts +121 -120
- package/tsconfig.tsbuildinfo +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,42 @@
|
|
|
1
|
+
## 0.12.45
|
|
2
|
+
|
|
3
|
+
### Patch Changes
|
|
4
|
+
|
|
5
|
+
- e9a778f: feat(config): add optional `postgres` pool config to `CoreConfig`
|
|
6
|
+
|
|
7
|
+
Postgres is a first-class adapter, so its runtime pool tuning now lives in the
|
|
8
|
+
core config (sibling to `workflow`), typed via the new `PostgresConfig`:
|
|
9
|
+
`maxPool`, `connectTimeout`, `idleTimeout`, `maxLifetime`, `statementTimeout`,
|
|
10
|
+
`prepare`. The connection string itself stays the flat `postgresUrl`/`sqliteDb`
|
|
11
|
+
field the CLI db commands read; this block is purely runtime pool options.
|
|
12
|
+
|
|
13
|
+
## 0.12.44
|
|
14
|
+
|
|
15
|
+
### Patch Changes
|
|
16
|
+
|
|
17
|
+
- 41ce2cb: Upgrade to TypeScript 6 and raise the minimum Node.js version to 22.
|
|
18
|
+
|
|
19
|
+
All packages now build against `typescript@^6.0.3` and declare `engines.node >= 22`. Internal tooling (`ts-json-schema-generator`, `zod-to-ts`) was bumped to TypeScript 6-compatible releases.
|
|
20
|
+
|
|
21
|
+
## 0.12.43
|
|
22
|
+
|
|
23
|
+
### Patch Changes
|
|
24
|
+
|
|
25
|
+
- a8022e5: fix(workflow): scope the step advisory lock to the claim, not execution
|
|
26
|
+
|
|
27
|
+
`executeWorkflowStep` held the step's advisory lock — and, in the Postgres
|
|
28
|
+
workflow service, the pooled DB connection backing it — across the entire step
|
|
29
|
+
body, including the step's own network and DB work. Under concurrency >= the DB
|
|
30
|
+
pool size this self-deadlocks: every running step pins a connection on its lock
|
|
31
|
+
transaction while its inner queries wait for a connection that never frees, so
|
|
32
|
+
nothing makes progress and the API hangs.
|
|
33
|
+
|
|
34
|
+
The lock is only needed to atomically _claim_ a step (read state + mark it
|
|
35
|
+
`running`); once a step is `running`, the existing status guard already prevents
|
|
36
|
+
any concurrent worker from re-running it. The lock now covers only the claim;
|
|
37
|
+
execution and result persistence run with the lock released and the connection
|
|
38
|
+
back in the pool.
|
|
39
|
+
|
|
1
40
|
## 0.12.42
|
|
2
41
|
|
|
3
42
|
### Patch Changes
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @module @pikku/core
|
|
3
3
|
*/
|
|
4
|
-
export type { CommonWireMeta, CoreConfig, CorePikkuMiddleware, CorePikkuMiddlewareConfig, CorePikkuMiddlewareFactory, CorePikkuMiddlewareGroup, CoreServices, CoreSingletonServices, CoreUserSession, CreateConfig, ServerLifecycle, FunctionMeta, FunctionRuntimeMeta, FunctionServicesMeta, FunctionWiresMeta, FunctionsMeta, FunctionsRuntimeMeta, JSONPrimitive, JSONValue, MakeRequired, MiddlewareMetadata, MiddlewarePriority, PermissionMetadata, PickOptional, PickRequired, PikkuAIMiddlewareHooks, PikkuWire, PikkuRawWire, PikkuWiringTypes, RequireAtLeastOne, SerializedError, WireServices, } from './types/core.types.js';
|
|
4
|
+
export type { CommonWireMeta, CoreConfig, CorePikkuMiddleware, CorePikkuMiddlewareConfig, CorePikkuMiddlewareFactory, CorePikkuMiddlewareGroup, CoreServices, CoreSingletonServices, CoreUserSession, CreateConfig, ServerLifecycle, FunctionMeta, FunctionRuntimeMeta, FunctionServicesMeta, FunctionWiresMeta, FunctionsMeta, FunctionsRuntimeMeta, JSONPrimitive, JSONValue, MakeRequired, MiddlewareMetadata, MiddlewarePriority, PermissionMetadata, PickOptional, PickRequired, PikkuAIMiddlewareHooks, PikkuWire, PikkuRawWire, PikkuWiringTypes, PostgresConfig, RequireAtLeastOne, SerializedError, WireServices, } from './types/core.types.js';
|
|
5
5
|
export { pikkuAIMiddleware, pikkuChannelMiddleware, pikkuChannelMiddlewareFactory, pikkuMiddleware, pikkuMiddlewareFactory, } from './types/core.types.js';
|
|
6
6
|
export type { CorePikkuAuth, CorePikkuAuthConfig, CorePikkuFunction, CorePikkuFunctionConfig, CorePikkuPermission, CorePikkuPermissionConfig, CorePikkuPermissionFactory, CorePikkuApprovalDescription, CorePermissionGroup, ZodLike, } from './function/functions.types.js';
|
|
7
7
|
export { pikkuAuth, pikkuPermission, pikkuPermissionFactory, pikkuApprovalDescription, } from './function/functions.types.js';
|
|
@@ -21,4 +21,5 @@ export declare const authAPIKey: import("../types/core.types.js").CorePikkuMiddl
|
|
|
21
21
|
logLevel?: import("../services/logger.js").LogLevel;
|
|
22
22
|
secrets?: {};
|
|
23
23
|
workflow?: import("../wirings/workflow/workflow.types.js").WorkflowServiceConfig;
|
|
24
|
+
postgres?: import("../types/core.types.js").PostgresConfig;
|
|
24
25
|
}>, import("../types/core.types.js").CoreUserSession>;
|
|
@@ -37,4 +37,5 @@ export declare const authBearer: import("../types/core.types.js").CorePikkuMiddl
|
|
|
37
37
|
logLevel?: import("../services/logger.js").LogLevel;
|
|
38
38
|
secrets?: {};
|
|
39
39
|
workflow?: import("../wirings/workflow/workflow.types.js").WorkflowServiceConfig;
|
|
40
|
+
postgres?: import("../types/core.types.js").PostgresConfig;
|
|
40
41
|
}>, CoreUserSession>;
|
|
@@ -36,4 +36,5 @@ export declare const authCookie: import("../types/core.types.js").CorePikkuMiddl
|
|
|
36
36
|
logLevel?: import("../services/logger.js").LogLevel;
|
|
37
37
|
secrets?: {};
|
|
38
38
|
workflow?: import("../wirings/workflow/workflow.types.js").WorkflowServiceConfig;
|
|
39
|
+
postgres?: import("../types/core.types.js").PostgresConfig;
|
|
39
40
|
}>, import("../types/core.types.js").CoreUserSession>;
|
|
@@ -43,4 +43,5 @@ export declare const cors: import("../types/core.types.js").CorePikkuMiddlewareF
|
|
|
43
43
|
logLevel?: import("../services/logger.js").LogLevel;
|
|
44
44
|
secrets?: {};
|
|
45
45
|
workflow?: import("../wirings/workflow/workflow.types.js").WorkflowServiceConfig;
|
|
46
|
+
postgres?: import("../types/core.types.js").PostgresConfig;
|
|
46
47
|
}>, import("../types/core.types.js").CoreUserSession>;
|
|
@@ -2,4 +2,5 @@ export declare const pikkuRemoteAuthMiddleware: import("../types/core.types.js")
|
|
|
2
2
|
logLevel?: import("../services/logger.js").LogLevel;
|
|
3
3
|
secrets?: {};
|
|
4
4
|
workflow?: import("../wirings/workflow/workflow.types.js").WorkflowServiceConfig;
|
|
5
|
+
postgres?: import("../types/core.types.js").PostgresConfig;
|
|
5
6
|
}>, import("../types/core.types.js").CoreUserSession>;
|
|
@@ -21,6 +21,7 @@ export declare const telemetryOuter: import("../types/core.types.js").CorePikkuM
|
|
|
21
21
|
logLevel?: import("../services/logger.js").LogLevel;
|
|
22
22
|
secrets?: {};
|
|
23
23
|
workflow?: import("../wirings/workflow/workflow.types.js").WorkflowServiceConfig;
|
|
24
|
+
postgres?: import("../types/core.types.js").PostgresConfig;
|
|
24
25
|
}>, import("../types/core.types.js").CoreUserSession>;
|
|
25
26
|
/**
|
|
26
27
|
* Inner telemetry middleware that captures function execution duration and user context.
|
|
@@ -44,4 +45,5 @@ export declare const telemetryInner: import("../types/core.types.js").CorePikkuM
|
|
|
44
45
|
logLevel?: import("../services/logger.js").LogLevel;
|
|
45
46
|
secrets?: {};
|
|
46
47
|
workflow?: import("../wirings/workflow/workflow.types.js").WorkflowServiceConfig;
|
|
48
|
+
postgres?: import("../types/core.types.js").PostgresConfig;
|
|
47
49
|
}>, import("../types/core.types.js").CoreUserSession>;
|
|
@@ -4,4 +4,5 @@ export declare const timeout: () => import("../types/core.types.js").CorePikkuMi
|
|
|
4
4
|
logLevel?: import("../services/logger.js").LogLevel;
|
|
5
5
|
secrets?: {};
|
|
6
6
|
workflow?: import("../wirings/workflow/workflow.types.js").WorkflowServiceConfig;
|
|
7
|
+
postgres?: import("../types/core.types.js").PostgresConfig;
|
|
7
8
|
}>, import("../types/core.types.js").CoreUserSession>;
|
|
@@ -137,6 +137,36 @@ export type PickOptional<T, K extends keyof T> = Partial<T> & Pick<T, K>;
|
|
|
137
137
|
export type RequireAtLeastOne<T> = {
|
|
138
138
|
[K in keyof T]-?: Required<Pick<T, K>> & Partial<Pick<T, Exclude<keyof T, K>>>;
|
|
139
139
|
}[keyof T];
|
|
140
|
+
/**
|
|
141
|
+
* Runtime options for the Postgres adapter (@pikku/kysely-postgres).
|
|
142
|
+
* The connection string itself stays the flat `postgresUrl` config field (the
|
|
143
|
+
* contract the CLI's db commands read); this block is purely runtime pool
|
|
144
|
+
* tuning that the CLI never touches.
|
|
145
|
+
*/
|
|
146
|
+
export interface PostgresConfig {
|
|
147
|
+
/** Max connections in the postgres.js pool. Defaults to postgres.js's 10. */
|
|
148
|
+
maxPool?: number;
|
|
149
|
+
/** Seconds to wait establishing a new connection before failing. */
|
|
150
|
+
connectTimeout?: number;
|
|
151
|
+
/** Close a pooled connection after it has been idle this many seconds. */
|
|
152
|
+
idleTimeout?: number;
|
|
153
|
+
/**
|
|
154
|
+
* Recycle a connection after this many seconds. Guards against stale TCP
|
|
155
|
+
* connections silently dropped by load balancers / proxies.
|
|
156
|
+
*/
|
|
157
|
+
maxLifetime?: number;
|
|
158
|
+
/**
|
|
159
|
+
* Server-side `statement_timeout` in milliseconds. A query running longer is
|
|
160
|
+
* cancelled, freeing its connection — defense against a runaway query pinning
|
|
161
|
+
* a pooled connection and exhausting the pool.
|
|
162
|
+
*/
|
|
163
|
+
statementTimeout?: number;
|
|
164
|
+
/**
|
|
165
|
+
* Set `false` behind a transaction-mode connection pooler (pgBouncer,
|
|
166
|
+
* Supabase pooler) that cannot use prepared statements.
|
|
167
|
+
*/
|
|
168
|
+
prepare?: boolean;
|
|
169
|
+
}
|
|
140
170
|
/**
|
|
141
171
|
* Interface for the core configuration settings of Pikku.
|
|
142
172
|
*/
|
|
@@ -146,6 +176,8 @@ export type CoreConfig<Config extends Record<string, unknown> = {}> = {
|
|
|
146
176
|
/** Secrets used by the application (optional). */
|
|
147
177
|
secrets?: {};
|
|
148
178
|
workflow?: WorkflowServiceConfig;
|
|
179
|
+
/** Runtime Postgres adapter options (pool sizing). */
|
|
180
|
+
postgres?: PostgresConfig;
|
|
149
181
|
} & Config;
|
|
150
182
|
/**
|
|
151
183
|
* Represents a core user session, which can be extended for more specific session information.
|
|
@@ -12,5 +12,6 @@ export declare const voiceOutput: (config?: {
|
|
|
12
12
|
logLevel?: import("../../services/logger.js").LogLevel;
|
|
13
13
|
secrets?: {};
|
|
14
14
|
workflow?: import("../workflow/workflow.types.js").WorkflowServiceConfig;
|
|
15
|
+
postgres?: import("../../types/core.types.js").PostgresConfig;
|
|
15
16
|
}>>;
|
|
16
17
|
export {};
|
|
@@ -103,4 +103,5 @@ export declare const rpcService: PikkuRPCService<import("../../types/core.types.
|
|
|
103
103
|
logLevel?: import("../../services/logger.js").LogLevel;
|
|
104
104
|
secrets?: {};
|
|
105
105
|
workflow?: import("../workflow/workflow.types.js").WorkflowServiceConfig;
|
|
106
|
+
postgres?: import("../../types/core.types.js").PostgresConfig;
|
|
106
107
|
}>, PikkuRPC>;
|
|
@@ -882,114 +882,120 @@ export class PikkuWorkflowService {
|
|
|
882
882
|
* Handles idempotency, RPC execution, result storage, retry logic, and orchestrator triggering
|
|
883
883
|
*/
|
|
884
884
|
async executeWorkflowStep(runId, stepName, rpcName, data, rpcService) {
|
|
885
|
-
//
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
//
|
|
894
|
-
if (stepState.status === 'running') {
|
|
895
|
-
return;
|
|
885
|
+
// Claim the step under the lock ONLY (atomic check-and-mark-running). Do NOT
|
|
886
|
+
// hold the advisory lock — and its pooled connection — across execution: once
|
|
887
|
+
// a step is 'running' the guard below makes any concurrent worker return
|
|
888
|
+
// early, so the work + result persistence run with the lock released. Holding
|
|
889
|
+
// the lock across executeGraphStep (network I/O + more pool queries) let
|
|
890
|
+
// concurrent steps exhaust the connection pool and self-deadlock.
|
|
891
|
+
const claimed = await this.withStepLock(runId, stepName, async () => {
|
|
892
|
+
const stepState = await this.getStepState(runId, stepName);
|
|
893
|
+
// Already succeeded, or already claimed by another worker — nothing to do.
|
|
894
|
+
if (stepState.status === 'succeeded' || stepState.status === 'running') {
|
|
895
|
+
return null;
|
|
896
896
|
}
|
|
897
|
-
//
|
|
897
|
+
// A 'failed' status means this is a retry — start a fresh 'running' attempt.
|
|
898
898
|
if (stepState.status === 'failed') {
|
|
899
|
-
|
|
899
|
+
return this.createRetryAttempt(stepState.stepId, 'running');
|
|
900
900
|
}
|
|
901
901
|
if (stepState.status === 'pending' || stepState.status === 'scheduled') {
|
|
902
902
|
await this.setStepRunning(stepState.stepId);
|
|
903
903
|
}
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
}
|
|
928
|
-
if (graphNodeId) {
|
|
929
|
-
result = await executeGraphStep(this, rpcService, runId, stepState.stepId, graphNodeId, rpcName, data, run.workflow);
|
|
904
|
+
return stepState;
|
|
905
|
+
});
|
|
906
|
+
// Nothing to execute: already succeeded, or another worker owns this step.
|
|
907
|
+
if (!claimed) {
|
|
908
|
+
return;
|
|
909
|
+
}
|
|
910
|
+
const stepState = claimed;
|
|
911
|
+
try {
|
|
912
|
+
let result;
|
|
913
|
+
const run = await this.getRun(runId);
|
|
914
|
+
if (!run) {
|
|
915
|
+
throw new Error(`Workflow run not found: ${runId}`);
|
|
916
|
+
}
|
|
917
|
+
const meta = pikkuState(null, 'workflows', 'meta');
|
|
918
|
+
const workflowMeta = meta[run.workflow];
|
|
919
|
+
const isGraphWorkflow = workflowMeta?.source === 'graph' ||
|
|
920
|
+
workflowMeta?.source === 'dynamic-workflow';
|
|
921
|
+
// Map the physical step key back to its logical node: a revisit instance
|
|
922
|
+
// is `node#N` (ordinal), which isn't a literal key in `nodes`.
|
|
923
|
+
let graphNodeId;
|
|
924
|
+
if (isGraphWorkflow && workflowMeta?.nodes) {
|
|
925
|
+
if (stepName in workflowMeta.nodes) {
|
|
926
|
+
graphNodeId = stepName;
|
|
930
927
|
}
|
|
931
928
|
else {
|
|
932
|
-
|
|
933
|
-
const
|
|
934
|
-
if (
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
929
|
+
const hash = stepName.lastIndexOf('#');
|
|
930
|
+
const base = hash > 0 ? stepName.slice(0, hash) : undefined;
|
|
931
|
+
if (base && base in workflowMeta.nodes)
|
|
932
|
+
graphNodeId = base;
|
|
933
|
+
}
|
|
934
|
+
}
|
|
935
|
+
if (graphNodeId) {
|
|
936
|
+
result = await executeGraphStep(this, rpcService, runId, stepState.stepId, graphNodeId, rpcName, data, run.workflow);
|
|
937
|
+
}
|
|
938
|
+
else {
|
|
939
|
+
// Check if rpcName refers to a sub-workflow
|
|
940
|
+
const subWorkflowMeta = meta[rpcName];
|
|
941
|
+
if (subWorkflowMeta) {
|
|
942
|
+
const childWire = {
|
|
943
|
+
type: 'workflow',
|
|
944
|
+
id: rpcName,
|
|
945
|
+
parentRunId: runId,
|
|
946
|
+
parentStepId: stepState.stepId,
|
|
947
|
+
pikkuUserId: rpcService.wire?.pikkuUserId,
|
|
948
|
+
};
|
|
949
|
+
const shouldInline = !getSingletonServices()?.queueService;
|
|
950
|
+
const { runId: childRunId } = await this.startWorkflow(rpcName, data, childWire, rpcService, { inline: shouldInline });
|
|
951
|
+
await this.setStepChildRunId(stepState.stepId, childRunId);
|
|
952
|
+
if (shouldInline) {
|
|
953
|
+
const childRun = await this.getRun(childRunId);
|
|
954
|
+
if (childRun?.status === 'failed') {
|
|
955
|
+
throw new Error(childRun.error?.message || 'Sub-workflow failed');
|
|
954
956
|
}
|
|
955
|
-
|
|
956
|
-
throw new
|
|
957
|
+
if (childRun?.status === 'cancelled') {
|
|
958
|
+
throw new Error('Sub-workflow was cancelled');
|
|
957
959
|
}
|
|
960
|
+
result = childRun?.output;
|
|
958
961
|
}
|
|
959
962
|
else {
|
|
960
|
-
|
|
963
|
+
throw new ChildWorkflowStartedException(runId, stepState.stepId, childRunId);
|
|
961
964
|
}
|
|
962
965
|
}
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
// Resume orchestrator to continue workflow
|
|
966
|
-
await this.resumeWorkflow(runId);
|
|
967
|
-
}
|
|
968
|
-
catch (error) {
|
|
969
|
-
if (error instanceof ChildWorkflowStartedException) {
|
|
970
|
-
this.logger?.debug(`Workflow step '${stepName}': child workflow ${error.childRunId} started, waiting for completion`);
|
|
971
|
-
return;
|
|
972
|
-
}
|
|
973
|
-
if (error instanceof RPCNotFoundError) {
|
|
974
|
-
await this.setStepError(stepState.stepId, error);
|
|
975
|
-
await this.updateRunStatus(runId, 'suspended', undefined, {
|
|
976
|
-
message: `RPC '${rpcName}' not found. Deploy the missing function and resume.`,
|
|
977
|
-
code: 'RPC_NOT_FOUND',
|
|
978
|
-
});
|
|
979
|
-
return;
|
|
966
|
+
else {
|
|
967
|
+
result = await this.invokeStepRpc(runId, stepName, stepState, rpcName, data, rpcService);
|
|
980
968
|
}
|
|
981
|
-
|
|
969
|
+
}
|
|
970
|
+
// Store result and mark succeeded
|
|
971
|
+
await this.setStepResult(stepState.stepId, result);
|
|
972
|
+
// Resume orchestrator to continue workflow
|
|
973
|
+
await this.resumeWorkflow(runId);
|
|
974
|
+
}
|
|
975
|
+
catch (error) {
|
|
976
|
+
if (error instanceof ChildWorkflowStartedException) {
|
|
977
|
+
this.logger?.debug(`Workflow step '${stepName}': child workflow ${error.childRunId} started, waiting for completion`);
|
|
978
|
+
return;
|
|
979
|
+
}
|
|
980
|
+
if (error instanceof RPCNotFoundError) {
|
|
982
981
|
await this.setStepError(stepState.stepId, error);
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
}
|
|
989
|
-
// Always throw so queue knows the job failed and can retry if needed
|
|
990
|
-
throw error;
|
|
982
|
+
await this.updateRunStatus(runId, 'suspended', undefined, {
|
|
983
|
+
message: `RPC '${rpcName}' not found. Deploy the missing function and resume.`,
|
|
984
|
+
code: 'RPC_NOT_FOUND',
|
|
985
|
+
});
|
|
986
|
+
return;
|
|
991
987
|
}
|
|
992
|
-
|
|
988
|
+
// Store error and mark failed
|
|
989
|
+
await this.setStepError(stepState.stepId, error);
|
|
990
|
+
const maxAttempts = (stepState.retries ?? DEFAULT_STEP_RETRIES) + 1;
|
|
991
|
+
const retriesExhausted = stepState.attemptCount >= maxAttempts;
|
|
992
|
+
if (retriesExhausted) {
|
|
993
|
+
// No more retries - resume orchestrator to mark workflow as failed
|
|
994
|
+
await this.resumeWorkflow(runId);
|
|
995
|
+
}
|
|
996
|
+
// Always throw so queue knows the job failed and can retry if needed
|
|
997
|
+
throw error;
|
|
998
|
+
}
|
|
993
999
|
}
|
|
994
1000
|
/**
|
|
995
1001
|
* Orchestrate workflow execution (called by orchestrator)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pikku/core",
|
|
3
|
-
"version": "0.12.
|
|
3
|
+
"version": "0.12.45",
|
|
4
4
|
"author": "yasser.fadl@gmail.com",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"module": "dist/index.js",
|
|
@@ -63,9 +63,9 @@
|
|
|
63
63
|
"devDependencies": {
|
|
64
64
|
"@types/node": "^24.11.0",
|
|
65
65
|
"tsx": "^4.21.0",
|
|
66
|
-
"typescript": "^
|
|
66
|
+
"typescript": "^6.0.3"
|
|
67
67
|
},
|
|
68
68
|
"engines": {
|
|
69
|
-
"node": ">=
|
|
69
|
+
"node": ">=22"
|
|
70
70
|
}
|
|
71
71
|
}
|
package/src/index.ts
CHANGED
package/src/types/core.types.ts
CHANGED
|
@@ -192,6 +192,37 @@ export type RequireAtLeastOne<T> = {
|
|
|
192
192
|
[K in keyof T]-?: Required<Pick<T, K>> & Partial<Pick<T, Exclude<keyof T, K>>>
|
|
193
193
|
}[keyof T]
|
|
194
194
|
|
|
195
|
+
/**
|
|
196
|
+
* Runtime options for the Postgres adapter (@pikku/kysely-postgres).
|
|
197
|
+
* The connection string itself stays the flat `postgresUrl` config field (the
|
|
198
|
+
* contract the CLI's db commands read); this block is purely runtime pool
|
|
199
|
+
* tuning that the CLI never touches.
|
|
200
|
+
*/
|
|
201
|
+
export interface PostgresConfig {
|
|
202
|
+
/** Max connections in the postgres.js pool. Defaults to postgres.js's 10. */
|
|
203
|
+
maxPool?: number
|
|
204
|
+
/** Seconds to wait establishing a new connection before failing. */
|
|
205
|
+
connectTimeout?: number
|
|
206
|
+
/** Close a pooled connection after it has been idle this many seconds. */
|
|
207
|
+
idleTimeout?: number
|
|
208
|
+
/**
|
|
209
|
+
* Recycle a connection after this many seconds. Guards against stale TCP
|
|
210
|
+
* connections silently dropped by load balancers / proxies.
|
|
211
|
+
*/
|
|
212
|
+
maxLifetime?: number
|
|
213
|
+
/**
|
|
214
|
+
* Server-side `statement_timeout` in milliseconds. A query running longer is
|
|
215
|
+
* cancelled, freeing its connection — defense against a runaway query pinning
|
|
216
|
+
* a pooled connection and exhausting the pool.
|
|
217
|
+
*/
|
|
218
|
+
statementTimeout?: number
|
|
219
|
+
/**
|
|
220
|
+
* Set `false` behind a transaction-mode connection pooler (pgBouncer,
|
|
221
|
+
* Supabase pooler) that cannot use prepared statements.
|
|
222
|
+
*/
|
|
223
|
+
prepare?: boolean
|
|
224
|
+
}
|
|
225
|
+
|
|
195
226
|
/**
|
|
196
227
|
* Interface for the core configuration settings of Pikku.
|
|
197
228
|
*/
|
|
@@ -202,6 +233,8 @@ export type CoreConfig<Config extends Record<string, unknown> = {}> = {
|
|
|
202
233
|
secrets?: {}
|
|
203
234
|
|
|
204
235
|
workflow?: WorkflowServiceConfig
|
|
236
|
+
/** Runtime Postgres adapter options (pool sizing). */
|
|
237
|
+
postgres?: PostgresConfig
|
|
205
238
|
} & Config
|
|
206
239
|
|
|
207
240
|
/**
|