-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathbackground-execution-demo.js
More file actions
205 lines (174 loc) Β· 6.01 KB
/
Copy pathbackground-execution-demo.js
File metadata and controls
205 lines (174 loc) Β· 6.01 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
#!/usr/bin/env node
// background-execution-demo.js - Demonstration of non-blocking background execution
console.log('π Background Execution System Demo\n');
// Simulate the key concepts of our background execution system
class BackgroundExecutionDemo {
constructor() {
this.activeJobs = new Map();
this.jobQueue = [];
this.maxConcurrentJobs = 3;
this.jobIdCounter = 0;
}
// Simulate starting a background job (non-blocking)
async *startBackgroundJob(taskName, duration = 2000) {
const jobId = `job_${++this.jobIdCounter}`;
console.log(`π Queuing job: ${taskName} (ID: ${jobId})`);
// Immediate response - UI not blocked
yield {
type: 'job_queued',
jobId,
taskName,
status: 'queued',
message: `Job ${taskName} queued for background processing`
};
// Start background execution
const jobPromise = this.executeInBackground(jobId, taskName, duration);
this.activeJobs.set(jobId, {
id: jobId,
taskName,
promise: jobPromise,
startTime: Date.now()
});
// Stream status updates
yield* this.streamJobStatus(jobId);
}
// Background execution (doesn't block UI)
async executeInBackground(jobId, taskName, duration) {
console.log(`π§ Background: Starting execution of ${taskName}`);
// Simulate work with progress updates
const steps = 5;
const stepDuration = duration / steps;
for (let i = 1; i <= steps; i++) {
await new Promise(resolve => setTimeout(resolve, stepDuration));
// Notify of progress (would trigger UI updates)
this.notifyProgress(jobId, i, steps, `Step ${i}/${steps} completed`);
}
console.log(`β
Background: Completed execution of ${taskName}`);
return { success: true, result: `${taskName} completed successfully` };
}
// Stream job status updates to UI
async *streamJobStatus(jobId) {
const maxWait = 10000; // 10 seconds
const pollInterval = 200; // 200ms
let elapsed = 0;
while (elapsed < maxWait) {
const job = this.activeJobs.get(jobId);
if (!job) {
yield {
type: 'job_completed',
jobId,
status: 'completed',
message: 'Background job completed'
};
return;
}
// Check if job is done
try {
const result = await Promise.race([
job.promise,
new Promise(resolve => setTimeout(() => resolve(null), pollInterval))
]);
if (result !== null) {
// Job completed
this.activeJobs.delete(jobId);
yield {
type: 'job_completed',
jobId,
status: 'completed',
result,
message: `Job completed: ${job.taskName}`
};
return;
}
} catch (error) {
// Job failed
this.activeJobs.delete(jobId);
yield {
type: 'job_failed',
jobId,
status: 'failed',
error: error.message,
message: `Job failed: ${job.taskName}`
};
return;
}
elapsed += pollInterval;
}
// Timeout - job continues in background
yield {
type: 'job_timeout',
jobId,
status: 'running',
message: 'UI timeout - job continues in background'
};
}
// Simulate progress notifications
notifyProgress(jobId, current, total, message) {
const progress = (current / total) * 100;
console.log(`π Progress [${jobId}]: ${progress.toFixed(0)}% - ${message}`);
}
// Get status of all background jobs
getJobsStatus() {
return Array.from(this.activeJobs.values()).map(job => ({
id: job.id,
taskName: job.taskName,
runningTime: Date.now() - job.startTime
}));
}
}
// Demonstration function
async function demonstrateBackgroundExecution() {
const executor = new BackgroundExecutionDemo();
console.log('π― Demonstrating non-blocking execution:\n');
// Start multiple background jobs
const jobs = [
executor.startBackgroundJob('Write Fibonacci File', 1500),
executor.startBackgroundJob('Process Data', 2000),
executor.startBackgroundJob('Generate Report', 1000)
];
// Simulate UI responsiveness while jobs run
const uiSimulation = async () => {
for (let i = 1; i <= 8; i++) {
console.log(`π±οΈ UI Action ${i}: User interaction processed immediately`);
await new Promise(resolve => setTimeout(resolve, 300));
}
};
// Process all jobs concurrently while maintaining UI responsiveness
const jobPromises = jobs.map(async (jobGenerator, index) => {
console.log(`\n--- Job ${index + 1} Status Updates ---`);
for await (const status of jobGenerator) {
console.log(`π‘ Job ${index + 1} Update:`, status.message);
if (status.type === 'job_completed' || status.type === 'job_failed') {
break;
}
}
});
// Run everything concurrently
await Promise.all([
...jobPromises,
uiSimulation()
]);
console.log('\nπ All jobs completed! UI remained responsive throughout.');
console.log('\nπ Final job status:', executor.getJobsStatus());
}
// Key benefits demonstration
function explainBenefits() {
console.log('\nπ Key Benefits of Background Execution System:');
console.log('');
console.log('1. π« Non-Blocking: UI never freezes during tool execution');
console.log('2. π‘ Streaming Updates: Real-time progress without polling');
console.log('3. π Concurrent Jobs: Multiple tools can run simultaneously');
console.log('4. πΎ Persistence: Jobs survive UI disconnections');
console.log('5. ποΈ Control: Jobs can be paused, resumed, or cancelled');
console.log('6. π Monitoring: Full visibility into job status and progress');
console.log('');
console.log('π― Result: Smooth, responsive user experience even with long-running tasks!');
}
// Run the demonstration
demonstrateBackgroundExecution()
.then(() => explainBenefits())
.catch(error => {
console.error('β Demo failed:', error);
process.exit(1);
});
export { BackgroundExecutionDemo };