Skip to content

Conversation

@d-klotz
Copy link
Contributor

@d-klotz d-klotz commented Jan 19, 2026

Summary

  • Add one-time job scheduling via AWS EventBridge Scheduler for integrations
  • Implement hexagonal architecture (Port/Adapter pattern) for testability
  • Auto-provision CloudFormation resources when webhooks.enabled: true

Changes

Core Package

  • Scheduler Commands (createSchedulerCommands): Schedule, delete, and check status of one-time jobs
  • SchedulerServiceInterface: Port defining the scheduling contract
  • EventBridgeSchedulerAdapter: Production adapter using AWS EventBridge
  • MockSchedulerAdapter: Local development adapter with in-memory storage
  • Factory: Auto-selects adapter based on environment

DevTools Package

  • SchedulerBuilder: Creates EventBridge ScheduleGroup and IAM roles
  • Auto-enables when any integration has webhooks.enabled: true

Environment Variables (auto-set by infrastructure)

  • SCHEDULER_ROLE_ARN - IAM role for EventBridge
  • SCHEDULER_PROVIDER - eventbridge or mock

Related Issues

Enables webhook auto-renewal for integrations (e.g., Zoho CRM notification channels).

📦 Published PR as canary version: 2.0.0--canary.531.5b60782.0

✨ Test out this PR locally via:

npm install @friggframework/core@2.0.0--canary.531.5b60782.0
npm install @friggframework/devtools@2.0.0--canary.531.5b60782.0
npm install @friggframework/eslint-config@2.0.0--canary.531.5b60782.0
npm install @friggframework/prettier-config@2.0.0--canary.531.5b60782.0
npm install @friggframework/schemas@2.0.0--canary.531.5b60782.0
npm install @friggframework/serverless-plugin@2.0.0--canary.531.5b60782.0
npm install @friggframework/test@2.0.0--canary.531.5b60782.0
npm install @friggframework/ui@2.0.0--canary.531.5b60782.0
# or 
yarn add @friggframework/core@2.0.0--canary.531.5b60782.0
yarn add @friggframework/devtools@2.0.0--canary.531.5b60782.0
yarn add @friggframework/eslint-config@2.0.0--canary.531.5b60782.0
yarn add @friggframework/prettier-config@2.0.0--canary.531.5b60782.0
yarn add @friggframework/schemas@2.0.0--canary.531.5b60782.0
yarn add @friggframework/serverless-plugin@2.0.0--canary.531.5b60782.0
yarn add @friggframework/test@2.0.0--canary.531.5b60782.0
yarn add @friggframework/ui@2.0.0--canary.531.5b60782.0

Add scheduler commands and infrastructure support for one-time job scheduling
using AWS EventBridge Scheduler. This enables integrations to schedule
delayed tasks like webhook renewal.

## Core Package (@friggframework/core)

### New: Scheduler Commands (application/commands/scheduler-commands.js)
- `createSchedulerCommands({ integrationName })` factory function
- `scheduleJob()` - Schedule one-time job targeting SQS queue
- `deleteJob()` - Delete scheduled job (graceful if not exists)
- `getJobStatus()` - Get schedule status

### New: Scheduler Infrastructure (infrastructure/scheduler/)
- `EventBridgeSchedulerAdapter` - AWS EventBridge Scheduler implementation
- `createSchedulerAdapter()` - Factory for scheduler adapters
- Supports `ActionAfterCompletion: DELETE` for auto-cleanup

### Exports
- Added `createSchedulerCommands` export from core index

## DevTools Package (@friggframework/devtools)

### New: SchedulerBuilder (infrastructure/domains/scheduler/)
- Creates `AWS::Scheduler::ScheduleGroup` resource
- Creates IAM Role for EventBridge Scheduler to send SQS messages
- Adds IAM statements for Lambda to manage schedules
- Sets `SCHEDULER_ROLE_ARN` and `SCHEDULER_PROVIDER` environment variables
- Auto-enables when integrations have webhooks configured

### Infrastructure Composer
- Added SchedulerBuilder to builder orchestrator
- Depends on IntegrationBuilder (needs queue ARNs)

## Usage Example

```javascript
const { createSchedulerCommands } = require('@friggframework/core');

const scheduler = createSchedulerCommands({ integrationName: 'zoho' });

await scheduler.scheduleJob({
    jobId: 'renewal-123',
    scheduledAt: new Date(Date.now() + 6 * 24 * 60 * 60 * 1000),
    event: 'REFRESH_WEBHOOK',
    payload: { integrationId: '123' },
    queueArn: process.env.INTEGRATION_QUEUE_ARN,
});
```

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@d-klotz d-klotz added release Create a release when this pr is merged prerelease This change is available in a prerelease. labels Jan 19, 2026
- Add MockSchedulerAdapter for in-memory scheduling in dev/test/local
- Update scheduler factory to auto-select provider based on STAGE
- Support explicit SCHEDULER_PROVIDER env var override
- Add helper methods for testing: _getSchedules, _clearSchedules, _simulateTrigger

This enables local testing of scheduled notification renewals without
requiring AWS EventBridge Scheduler infrastructure.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
d-klotz and others added 8 commits January 19, 2026 16:26
Add {INTEGRATION}_QUEUE_ARN environment variable alongside
{INTEGRATION}_QUEUE_URL. This is needed for EventBridge Scheduler
to target integration queues for scheduled jobs.

- For stack-owned queues: use Fn::GetAtt to get ARN
- For external queues: derive ARN from URL

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Change scheduler commands to accept queueUrl instead of queueArn.
The ARN is now derived internally from the URL, which follows the
standard Frigg pattern of using {INTEGRATION}_QUEUE_URL as the
primary queue identifier.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add documentation for the scheduler commands system to SKILL.md and CLAUDE.md:
- Usage examples for scheduleJob, deleteJob, getJobStatus
- Environment variables (SCHEDULER_ROLE_ARN, SCHEDULER_DLQ_ARN, SCHEDULER_PROVIDER)
- Key features (EventBridge Scheduler, mock for local dev, queue URL handling)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Create SchedulerServiceInterface as the Port defining the contract
- Update EventBridgeSchedulerAdapter to extend the interface
- Update MockSchedulerAdapter to extend interface with proper validation
- Rename scheduler-factory.js to scheduler-service-factory.js
- Add dependency injection support to createSchedulerCommands
- Standardize return shapes for consistency

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…ility alias

The hexagonal architecture refactoring is complete. All code now uses
createSchedulerService directly - the deprecated alias has no usages.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…agnostic naming

- Remove SCHEDULER_PROVIDER=eventbridge from scheduler-builder.js to allow
  auto-detection based on stage (dev/test/local → mock, prod/staging → eventbridge)
- Rename interface parameters for provider-agnostic clarity:
  - targetArn → queueResourceId
  - scheduleArn → scheduledJobId
- Update all adapters and commands to use new naming convention
- MockScheduler now returns generic ID format (mock-job-{name})

Fixes the '[object Object]' error when running locally due to CloudFormation
intrinsic not resolving for SCHEDULER_ROLE_ARN.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Remove hardcoded SCHEDULE_GROUP_NAME constant from builder and adapter
- Use ${self:service}-${self:provider.stage}-schedules naming pattern
- Pass SCHEDULE_GROUP_NAME as environment variable to Lambda functions
- Read schedule group name from env var with backwards-compatible fallback
- Update IAM policy to reference CloudFormation resource dynamically

This allows multiple stages (dev, prod) to be deployed in the same
AWS account without resource name conflicts.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@sonarqubecloud
Copy link

Copy link
Contributor

@roboli roboli left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

prerelease This change is available in a prerelease. release Create a release when this pr is merged

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants