Files
OpenNoodl/dev-docs/tasks/phase-11-cloud-functions/CF11-003-wait-delay-nodes/README.md
Richard Osborne ddcb9cd02e feat: Phase 5 BYOB foundation + Phase 3 GitHub integration
Phase 5 - BYOB Backend (TASK-007A/B):
- LocalSQL Adapter with full CloudStore API compatibility
- QueryBuilder translates Parse-style queries to SQL
- SchemaManager with PostgreSQL/Supabase export
- LocalBackendServer with REST endpoints
- BackendManager with IPC handlers for Electron
- In-memory fallback when better-sqlite3 unavailable

Phase 3 - GitHub Panel (GIT-004):
- Issues tab with list/detail views
- Pull Requests tab with list/detail views
- GitHub API client with OAuth support
- Repository info hook integration

Phase 3 - Editor UX Bugfixes (TASK-013):
- Legacy runtime detection banners
- Read-only enforcement for legacy projects
- Code editor modal close improvements
- Property panel stuck state fix
- Blockly node deletion and UI polish

Phase 11 - Cloud Functions Planning:
- Architecture documentation for workflow automation
- Execution history storage schema design
- Canvas overlay concept for debugging

Docs: Updated LEARNINGS.md and COMMON-ISSUES.md
2026-01-15 17:37:15 +01:00

174 lines
4.3 KiB
Markdown

# CF11-003: Wait/Delay Nodes
## Metadata
| Field | Value |
| ------------------ | ------------------------------------ |
| **ID** | CF11-003 |
| **Phase** | Phase 11 |
| **Series** | 1 - Advanced Workflow Nodes |
| **Priority** | 🟢 Medium |
| **Difficulty** | 🟢 Low |
| **Estimated Time** | 4-6 hours |
| **Prerequisites** | Phase 5 TASK-007C (Workflow Runtime) |
| **Branch** | `feature/cf11-003-delay-nodes` |
## Objective
Create timing-related workflow nodes: Wait for explicit delays, Wait Until for scheduled execution, and debounce utilities - essential for rate limiting and scheduled workflows.
## Background
Workflows often need timing control:
- **Wait**: Pause execution for a duration (rate limiting APIs)
- **Wait Until**: Execute at a specific time (scheduled tasks)
- **Debounce**: Prevent rapid repeated execution
## Scope
### In Scope
- [ ] Wait Node (delay for X milliseconds)
- [ ] Wait Until Node (wait until specific time)
- [ ] Debounce Node (rate limit execution)
### Out of Scope
- Cron scheduling (handled by triggers)
- Throttle node (future)
## Technical Approach
### Wait Node
```typescript
const WaitNode = {
name: 'Workflow Wait',
displayName: 'Wait',
category: 'Workflow Logic',
inputs: {
run: { type: 'signal' },
duration: { type: 'number', displayName: 'Duration (ms)', default: 1000 },
unit: {
type: 'enum',
options: ['milliseconds', 'seconds', 'minutes', 'hours'],
default: 'milliseconds'
}
},
outputs: {
done: { type: 'signal', displayName: 'Done' }
},
async run(context) {
let ms = context.inputs.duration || 1000;
const unit = context.inputs.unit || 'milliseconds';
// Convert to milliseconds
const multipliers = {
milliseconds: 1,
seconds: 1000,
minutes: 60 * 1000,
hours: 60 * 60 * 1000
};
ms = ms * (multipliers[unit] || 1);
await new Promise((resolve) => setTimeout(resolve, ms));
context.triggerOutput('done');
}
};
```
### Wait Until Node
```typescript
const WaitUntilNode = {
name: 'Workflow Wait Until',
displayName: 'Wait Until',
category: 'Workflow Logic',
inputs: {
run: { type: 'signal' },
targetTime: { type: 'string', displayName: 'Target Time (ISO)' },
targetDate: { type: 'date', displayName: 'Target Date' }
},
outputs: {
done: { type: 'signal' },
skipped: { type: 'signal', displayName: 'Already Passed' }
},
async run(context) {
const target = context.inputs.targetDate || new Date(context.inputs.targetTime);
const now = Date.now();
const targetMs = target.getTime();
if (targetMs <= now) {
// Time already passed
context.triggerOutput('skipped');
return;
}
const waitTime = targetMs - now;
await new Promise((resolve) => setTimeout(resolve, waitTime));
context.triggerOutput('done');
}
};
```
### Debounce Node
```typescript
const DebounceNode = {
name: 'Workflow Debounce',
displayName: 'Debounce',
category: 'Workflow Logic',
inputs: {
run: { type: 'signal' },
delay: { type: 'number', default: 500 }
},
outputs: {
trigger: { type: 'signal' }
},
setup(context) {
context._debounceTimer = null;
},
run(context) {
if (context._debounceTimer) {
clearTimeout(context._debounceTimer);
}
context._debounceTimer = setTimeout(() => {
context.triggerOutput('trigger');
context._debounceTimer = null;
}, context.inputs.delay || 500);
}
};
```
## Implementation Steps
1. **Wait Node (2h)** - Simple delay, unit conversion
2. **Wait Until Node (2h)** - Date parsing, time calculation
3. **Debounce Node (1h)** - Timer management
4. **Testing (1h)** - Unit tests
## Success Criteria
- [ ] Wait delays for specified duration
- [ ] Wait supports multiple time units
- [ ] Wait Until triggers at target time
- [ ] Wait Until handles past times gracefully
- [ ] Debounce prevents rapid triggers
## References
- [CF11-001 Logic Nodes](../CF11-001-logic-nodes/README.md)
- [n8n Wait Node](https://docs.n8n.io/integrations/builtin/core-nodes/n8n-nodes-base.wait/)