@donkeylabs/server 2.0.31 → 2.0.33

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/docs/workflows.md CHANGED
@@ -97,9 +97,12 @@ Limit concurrent instances per workflow name:
97
97
  const server = new AppServer({
98
98
  db,
99
99
  workflows: {
100
- concurrentWorkflows: 1, // 0 = unlimited
100
+ concurrentWorkflows: 1, // default for all workflows (0 = unlimited)
101
101
  },
102
102
  });
103
+
104
+ // Per-register override
105
+ ctx.core.workflows.register(orderWorkflow, { maxConcurrent: 1 });
103
106
  ```
104
107
 
105
108
  ### 3. Track Progress
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@donkeylabs/server",
3
- "version": "2.0.31",
3
+ "version": "2.0.33",
4
4
  "type": "module",
5
5
  "description": "Type-safe plugin system for building RPC-style APIs with Bun",
6
6
  "main": "./src/index.ts",
@@ -766,7 +766,7 @@ export interface WorkflowsConfig {
766
766
  sqlitePragmas?: SqlitePragmaConfig;
767
767
  /** Disable in-process watchdog timers (use external watchdog instead) */
768
768
  useWatchdog?: boolean;
769
- /** Max concurrent instances per workflow name (0 = unlimited, default: 0) */
769
+ /** Default max concurrent instances per workflow name (0 = unlimited, default: 0) */
770
770
  concurrentWorkflows?: number;
771
771
  /** Resume strategy for orphaned workflows (default: "blocking") */
772
772
  resumeStrategy?: WorkflowResumeStrategy;
@@ -796,6 +796,8 @@ export interface WorkflowRegisterOptions {
796
796
  * workflows.register(myWorkflow, { modulePath: import.meta.url });
797
797
  */
798
798
  modulePath?: string;
799
+ /** Max concurrent instances for this workflow (overrides defaults) */
800
+ maxConcurrent?: number;
799
801
  }
800
802
 
801
803
  export interface Workflows {
@@ -874,6 +876,7 @@ class WorkflowsImpl implements Workflows {
874
876
  private sqlitePragmas?: SqlitePragmaConfig;
875
877
  private useWatchdog: boolean;
876
878
  private concurrentWorkflows: number;
879
+ private workflowConcurrencyOverrides = new Map<string, number>();
877
880
  private resumeStrategy!: WorkflowResumeStrategy;
878
881
  private workflowModulePaths = new Map<string, string>();
879
882
  private isolatedProcesses = new Map<string, IsolatedProcessInfo>();
@@ -1002,6 +1005,10 @@ class WorkflowsImpl implements Workflows {
1002
1005
  }
1003
1006
 
1004
1007
  this.definitions.set(definition.name, definition);
1008
+
1009
+ if (options?.maxConcurrent !== undefined) {
1010
+ this.workflowConcurrencyOverrides.set(definition.name, options.maxConcurrent);
1011
+ }
1005
1012
  }
1006
1013
 
1007
1014
  async start<T = any>(workflowName: string, input: T): Promise<string> {
@@ -1010,12 +1017,13 @@ class WorkflowsImpl implements Workflows {
1010
1017
  throw new Error(`Workflow "${workflowName}" is not registered`);
1011
1018
  }
1012
1019
 
1013
- if (this.concurrentWorkflows > 0) {
1020
+ const limit = this.getConcurrencyLimit(workflowName);
1021
+ if (limit > 0) {
1014
1022
  const running = await this.adapter.getInstancesByWorkflow(workflowName, "running");
1015
1023
  const pending = await this.adapter.getInstancesByWorkflow(workflowName, "pending");
1016
- if (running.length + pending.length >= this.concurrentWorkflows) {
1024
+ if (running.length + pending.length >= limit) {
1017
1025
  throw new Error(
1018
- `Workflow "${workflowName}" has reached its concurrency limit (${this.concurrentWorkflows})`
1026
+ `Workflow "${workflowName}" has reached its concurrency limit (${limit})`
1019
1027
  );
1020
1028
  }
1021
1029
  }
@@ -2005,6 +2013,13 @@ class WorkflowsImpl implements Workflows {
2005
2013
  await this.adapter.updateInstance(instanceId, { metadata });
2006
2014
  }
2007
2015
 
2016
+ private getConcurrencyLimit(workflowName: string): number {
2017
+ if (this.workflowConcurrencyOverrides.has(workflowName)) {
2018
+ return this.workflowConcurrencyOverrides.get(workflowName) ?? 0;
2019
+ }
2020
+ return this.concurrentWorkflows;
2021
+ }
2022
+
2008
2023
  private async markOrphanedAsFailed(
2009
2024
  instances: WorkflowInstance[],
2010
2025
  reason: string