|
| 1 | +# Workflow Load Tests |
| 2 | + |
| 3 | +These local-only Artillery scenarios exercise `POST /api/workflows/[id]/execute` in async mode. |
| 4 | + |
| 5 | +## Requirements |
| 6 | + |
| 7 | +- The app should be running locally, for example with `bun run dev:full` |
| 8 | +- Each scenario needs valid workflow IDs and API keys |
| 9 | +- All scenarios default to `http://localhost:3000` |
| 10 | + |
| 11 | +The default rates are tuned for these local limits: |
| 12 | + |
| 13 | +- `ADMISSION_GATE_MAX_INFLIGHT=500` |
| 14 | +- `DISPATCH_MAX_QUEUE_PER_WORKSPACE=1000` |
| 15 | +- `DISPATCH_MAX_QUEUE_GLOBAL=50000` |
| 16 | +- `WORKSPACE_CONCURRENCY_FREE=5` |
| 17 | +- `WORKSPACE_CONCURRENCY_PRO=50` |
| 18 | +- `WORKSPACE_CONCURRENCY_TEAM=200` |
| 19 | +- `WORKSPACE_CONCURRENCY_ENTERPRISE=200` |
| 20 | + |
| 21 | +That means the defaults are intentionally aimed at forcing queueing for a Free workspace without overwhelming a single local dev server process. |
| 22 | + |
| 23 | +## Baseline Concurrency |
| 24 | + |
| 25 | +Use this to ramp traffic into one workflow and observe normal queueing behavior. |
| 26 | + |
| 27 | +Default profile: |
| 28 | + |
| 29 | +- Starts at `2` requests per second |
| 30 | +- Ramps to `8` requests per second |
| 31 | +- Holds there for `20` seconds |
| 32 | +- Good for validating queueing against a Free workspace concurrency of `5` |
| 33 | + |
| 34 | +```bash |
| 35 | +WORKFLOW_ID=<workflow-id> \ |
| 36 | +SIM_API_KEY=<api-key> \ |
| 37 | +bun run load:workflow:baseline |
| 38 | +``` |
| 39 | + |
| 40 | +Optional variables: |
| 41 | + |
| 42 | +- `BASE_URL` |
| 43 | +- `WARMUP_DURATION` |
| 44 | +- `WARMUP_RATE` |
| 45 | +- `PEAK_RATE` |
| 46 | +- `HOLD_DURATION` |
| 47 | + |
| 48 | +For higher-plan workspaces, a good local starting point is: |
| 49 | + |
| 50 | +- Pro: `PEAK_RATE=20` to `40` |
| 51 | +- Team or Enterprise: `PEAK_RATE=50` to `100` |
| 52 | + |
| 53 | +## Queueing Waves |
| 54 | + |
| 55 | +Use this to send repeated bursts to one workflow in the same workspace. |
| 56 | + |
| 57 | +Default profile: |
| 58 | + |
| 59 | +- Wave 1: `6` requests per second for `10` seconds |
| 60 | +- Wave 2: `8` requests per second for `15` seconds |
| 61 | +- Wave 3: `10` requests per second for `20` seconds |
| 62 | +- Quiet gaps: `5` seconds |
| 63 | + |
| 64 | +```bash |
| 65 | +WORKFLOW_ID=<workflow-id> \ |
| 66 | +SIM_API_KEY=<api-key> \ |
| 67 | +bun run load:workflow:waves |
| 68 | +``` |
| 69 | + |
| 70 | +Optional variables: |
| 71 | + |
| 72 | +- `BASE_URL` |
| 73 | +- `WAVE_ONE_DURATION` |
| 74 | +- `WAVE_ONE_RATE` |
| 75 | +- `QUIET_DURATION` |
| 76 | +- `WAVE_TWO_DURATION` |
| 77 | +- `WAVE_TWO_RATE` |
| 78 | +- `WAVE_THREE_DURATION` |
| 79 | +- `WAVE_THREE_RATE` |
| 80 | + |
| 81 | +## Two-Workspace Isolation |
| 82 | + |
| 83 | +Use this to send mixed traffic to two workflows from different workspaces and compare whether one workspace's queue pressure appears to affect the other. |
| 84 | + |
| 85 | +Default profile: |
| 86 | + |
| 87 | +- Total rate: `9` requests per second for `30` seconds |
| 88 | +- Weight split: `8:1` |
| 89 | +- In practice this sends heavy pressure to workspace A while still sending a light stream to workspace B |
| 90 | + |
| 91 | +```bash |
| 92 | +WORKFLOW_ID_A=<workspace-a-workflow-id> \ |
| 93 | +SIM_API_KEY_A=<workspace-a-api-key> \ |
| 94 | +WORKFLOW_ID_B=<workspace-b-workflow-id> \ |
| 95 | +SIM_API_KEY_B=<workspace-b-api-key> \ |
| 96 | +bun run load:workflow:isolation |
| 97 | +``` |
| 98 | + |
| 99 | +Optional variables: |
| 100 | + |
| 101 | +- `BASE_URL` |
| 102 | +- `ISOLATION_DURATION` |
| 103 | +- `TOTAL_RATE` |
| 104 | +- `WORKSPACE_A_WEIGHT` |
| 105 | +- `WORKSPACE_B_WEIGHT` |
| 106 | + |
| 107 | +## Notes |
| 108 | + |
| 109 | +- `load:workflow` is an alias for `load:workflow:baseline` |
| 110 | +- All scenarios send `x-execution-mode: async` |
| 111 | +- Artillery output will show request counts and response codes, which is usually enough for quick local verification |
| 112 | +- At these defaults, you should observe queueing behavior before you approach `ADMISSION_GATE_MAX_INFLIGHT=500` or `DISPATCH_MAX_QUEUE_PER_WORKSPACE=1000` |
| 113 | +- If you still see lots of `429` or `ETIMEDOUT` responses locally, lower the rates again before increasing durations |
0 commit comments