mirror of
https://github.com/The-Low-Code-Foundation/OpenNoodl.git
synced 2026-03-08 10:03:31 +01:00
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
174 lines
4.3 KiB
Markdown
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/)
|