feat: Implement distributed locking in build worker#14
Conversation
… var - Add getGitHubToken() function to retrieve PAT from common environment - GitHub PAT stored at /laco/cmn/github/pat/cloud-apps (cross-environment) - Support local development with GITHUB_PAT_CLOUD_APPS env var - Remove TODO comments and temporary GITHUB_TOKEN workaround This fixes the SSM parameter access issue where the build worker couldn't access the GitHub PAT needed for repository_dispatch API. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
## Changes ### New Shared Modules - build-lock.ts: BuildLockManager with DynamoDB-based distributed locking - acquireLock(): Conditional write to acquire lock - releaseLock(): Mark as COMPLETED/FAILED - getLock(): Get current lock status - isLocked(): Check if operation in progress - command-config.ts: Centralized command configuration - Define lock requirements per command - /build: requiresLock=true, TTL=10min - /deploy: requiresLock=true, TTL=30min - /status, /echo: requiresLock=false ### Updated Build Worker - Import buildLockManager - Acquire lock before processing - If locked: notify user (ephemeral), skip processing - If acquired: proceed with build - Release lock on success/failure ## User Experience Lock acquired: "🔨 Building router..." (visible to channel) Lock held by another user: "⚠️ Build already in progress Started by: alice Started: 30s ago Please wait for the current build to complete." (ephemeral) ## Problem Solved Prevents duplicate GitHub Actions triggers when multiple users request the same build simultaneously. 🤖 Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com>
| private tableName: string; | ||
|
|
||
| constructor() { | ||
| const config = getConfig(); |
Check failure
Code scanning / CodeQL
Invocation of non-function Error
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI about 2 months ago
In general, to fix “invocation of non‑function” errors, you either (1) ensure the imported/assigned value is actually a function, or (2) guard before calling it and handle the error path explicitly. Since we are constrained to changes within this file and cannot alter the ./config module or change existing imports, the appropriate approach is to validate getConfig at the call site and avoid calling it if it is not a function.
Concretely, in applications/chatops/slack-bot/src/shared/build-lock.ts, update the BuildLockManager constructor to:
- Check that
getConfigis a function before invoking it. - If it is not a function, throw a descriptive error (or log and throw) instead of calling it, preventing a cryptic “is not a function” crash.
- Optionally give a type-safe fallback (e.g.,
neverafter throwing) so TypeScript remains happy, but that is not strictly necessary if we just throw and then use the result.
The minimal change is to replace:
constructor() {
const config = getConfig();
this.tableName = `${config.orgPrefix}-${config.environment}-chatbot-build-locks`;
}with a constructor that:
- Validates
typeof getConfig === 'function'. - Throws an
Errorif the validation fails. - Calls
getConfig()only in the safe branch and uses the returnedconfigas before.
No new imports are required; we can use the built‑in Error and existing logger if desired (but using Error alone is sufficient and keeps changes minimal).
| @@ -38,6 +38,9 @@ | ||
| private tableName: string; | ||
|
|
||
| constructor() { | ||
| if (typeof getConfig !== 'function') { | ||
| throw new Error('getConfig is not a function. Ensure ./config exports a callable getConfig.'); | ||
| } | ||
| const config = getConfig(); | ||
| this.tableName = `${config.orgPrefix}-${config.environment}-chatbot-build-locks`; | ||
| } |
Replace command-specific workers with unified quadrant workers for better scalability and maintainability. **Workers (routing layer):** - Remove: echo, build, deploy, status workers (command-specific) - Add: SR (short-read) and LW (long-write) unified workers - SR worker handles: /echo and future fast read commands - LW worker handles: /build, /deploy and future write commands **Handlers (business logic layer):** - Extract command logic into reusable handlers - handlers/echo.ts - Echo command logic - handlers/build.ts - Build command logic - Workers route to handlers based on command registry 1. **Extensibility**: New commands just need handler registration 2. **DRY**: Shared worker infrastructure for similar command types 3. **Performance**: Optimized timeouts and concurrency per quadrant 4. **Maintainability**: Clear separation of routing vs business logic - Build system: package.sh, Makefile, component-config.sh - CI/CD: slack-build.yml workflow - Local dev: LocalStack setup, .env.local.example - Documentation: CONFIGURATION.md, LOCAL-TESTING.md Aligns with cloud-sandbox PR #14 which provisions: - laco-plt-chatbot-command-sr-sqs queue - laco-plt-chatbot-command-lw-sqs queue - laco-plt-chatbot-command-sr-worker Lambda - laco-plt-chatbot-command-lw-worker Lambda
Replace command-specific workers with unified quadrant workers for better scalability and maintainability. **Workers (routing layer):** - Remove: echo, build, deploy, status workers (command-specific) - Add: SR (short-read) and LW (long-write) unified workers - SR worker handles: /echo and future fast read commands - LW worker handles: /build, /deploy and future write commands **Handlers (business logic layer):** - Extract command logic into reusable handlers - handlers/echo.ts - Echo command logic - handlers/build.ts - Build command logic - Workers route to handlers based on command registry 1. **Extensibility**: New commands just need handler registration 2. **DRY**: Shared worker infrastructure for similar command types 3. **Performance**: Optimized timeouts and concurrency per quadrant 4. **Maintainability**: Clear separation of routing vs business logic - Build system: package.sh, Makefile, component-config.sh - CI/CD: slack-build.yml workflow - Local dev: LocalStack setup, .env.local.example - Documentation: CONFIGURATION.md, LOCAL-TESTING.md Aligns with cloud-sandbox PR #14 which provisions: - laco-plt-chatbot-command-sr-sqs queue - laco-plt-chatbot-command-lw-sqs queue - laco-plt-chatbot-command-sr-worker Lambda - laco-plt-chatbot-command-lw-worker Lambda
Replace command-specific workers with unified quadrant workers for better scalability and maintainability. **Workers (routing layer):** - Remove: echo, build, deploy, status workers (command-specific) - Add: SR (short-read) and LW (long-write) unified workers - SR worker handles: /echo and future fast read commands - LW worker handles: /build, /deploy and future write commands **Handlers (business logic layer):** - Extract command logic into reusable handlers - handlers/echo.ts - Echo command logic - handlers/build.ts - Build command logic - Workers route to handlers based on command registry 1. **Extensibility**: New commands just need handler registration 2. **DRY**: Shared worker infrastructure for similar command types 3. **Performance**: Optimized timeouts and concurrency per quadrant 4. **Maintainability**: Clear separation of routing vs business logic - Build system: package.sh, Makefile, component-config.sh - CI/CD: slack-build.yml workflow - Local dev: LocalStack setup, .env.local.example - Documentation: CONFIGURATION.md, LOCAL-TESTING.md Aligns with cloud-sandbox PR #14 which provisions: - laco-plt-chatbot-command-sr-sqs queue - laco-plt-chatbot-command-lw-sqs queue - laco-plt-chatbot-command-sr-worker Lambda - laco-plt-chatbot-command-lw-worker Lambda
Summary
Key Changes
Implementation Details
{command}-{component}-{environment}(e.g.,build-router-plt)Test Plan
🤖 Generated with Claude Code