interaqt 0.3.0 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/agent/.claude/agents/code-generation-handler.md +2 -0
- package/agent/.claude/agents/computation-generation-handler.md +1 -0
- package/agent/.claude/agents/implement-design-handler.md +4 -13
- package/agent/.claude/agents/requirements-analysis-handler.md +46 -14
- package/agent/agentspace/knowledge/generator/api-reference.md +3378 -0
- package/agent/agentspace/knowledge/generator/basic-interaction-generation.md +377 -0
- package/agent/agentspace/knowledge/generator/computation-analysis.md +307 -0
- package/agent/agentspace/knowledge/generator/computation-implementation.md +959 -0
- package/agent/agentspace/knowledge/generator/data-analysis.md +463 -0
- package/agent/agentspace/knowledge/generator/entity-relation-generation.md +395 -0
- package/agent/agentspace/knowledge/generator/permission-implementation.md +460 -0
- package/agent/agentspace/knowledge/generator/permission-test-implementation.md +870 -0
- package/agent/agentspace/knowledge/generator/test-implementation.md +674 -0
- package/agent/agentspace/knowledge/usage/00-mindset-shift.md +322 -0
- package/agent/agentspace/knowledge/usage/01-core-concepts.md +131 -0
- package/agent/agentspace/knowledge/usage/02-define-entities-properties.md +407 -0
- package/agent/agentspace/knowledge/usage/03-entity-relations.md +599 -0
- package/agent/agentspace/knowledge/usage/04-reactive-computations.md +2186 -0
- package/agent/agentspace/knowledge/usage/05-interactions.md +1411 -0
- package/agent/agentspace/knowledge/usage/06-attributive-permissions.md +10 -0
- package/agent/agentspace/knowledge/usage/07-payload-parameters.md +593 -0
- package/agent/agentspace/knowledge/usage/08-activities.md +863 -0
- package/agent/agentspace/knowledge/usage/09-filtered-entities.md +784 -0
- package/agent/agentspace/knowledge/usage/10-async-computations.md +734 -0
- package/agent/agentspace/knowledge/usage/11-global-dictionaries.md +942 -0
- package/agent/agentspace/knowledge/usage/12-data-querying.md +1033 -0
- package/agent/agentspace/knowledge/usage/13-testing.md +1201 -0
- package/agent/agentspace/knowledge/usage/14-api-reference.md +1606 -0
- package/agent/agentspace/knowledge/usage/15-entity-crud-patterns.md +1122 -0
- package/agent/agentspace/knowledge/usage/16-frontend-page-design-guide.md +485 -0
- package/agent/agentspace/knowledge/usage/17-performance-optimization.md +283 -0
- package/agent/agentspace/knowledge/usage/18-api-exports-reference.md +176 -0
- package/agent/agentspace/knowledge/usage/19-common-anti-patterns.md +563 -0
- package/agent/agentspace/knowledge/usage/README.md +148 -0
- package/package.json +1 -1
|
@@ -0,0 +1,734 @@
|
|
|
1
|
+
# How to Use Async Computations
|
|
2
|
+
|
|
3
|
+
Async computations are an advanced feature of the interaqt framework that allow calling external APIs, performing time-consuming operations, or executing complex data processing during reactive computation processes. This chapter will detail how to implement and use async computations at different levels.
|
|
4
|
+
|
|
5
|
+
## Understanding Async Computation Scenarios
|
|
6
|
+
|
|
7
|
+
### When You Need Async Computations
|
|
8
|
+
|
|
9
|
+
Async computations are suitable for the following scenarios:
|
|
10
|
+
|
|
11
|
+
- **External API calls**: Need to fetch data from third-party services
|
|
12
|
+
- **Complex algorithm processing**: Operations requiring significant computation time
|
|
13
|
+
- **Machine learning inference**: Calling AI models for predictions
|
|
14
|
+
- **Data aggregation analysis**: Statistical computations requiring processing of large amounts of data
|
|
15
|
+
- **File processing**: Time-consuming operations like image processing, document conversion
|
|
16
|
+
|
|
17
|
+
### Advantages of Async Computations
|
|
18
|
+
|
|
19
|
+
```typescript
|
|
20
|
+
// Limitations of traditional sync computations
|
|
21
|
+
class SyncComputation {
|
|
22
|
+
compute(deps: any) {
|
|
23
|
+
// Cannot call async operations here
|
|
24
|
+
// const result = await fetchFromAPI(); // ❌ Not supported
|
|
25
|
+
return simpleCalculation(deps);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Advantages of async computations
|
|
30
|
+
class AsyncComputation {
|
|
31
|
+
async compute(deps: any) {
|
|
32
|
+
// ✅ Supports async operations
|
|
33
|
+
const externalData = await fetchFromAPI();
|
|
34
|
+
const result = await complexAnalysis(deps, externalData);
|
|
35
|
+
return ComputationResult.async(result);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
async asyncReturn(result: any, args: any) {
|
|
39
|
+
// ✅ Handle async return results
|
|
40
|
+
return processAsyncResult(result, args);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### Supported Computation Types
|
|
46
|
+
|
|
47
|
+
The framework supports three types of async computations:
|
|
48
|
+
|
|
49
|
+
1. **Global async computations**: Global-level computations with results stored in Dictionary
|
|
50
|
+
2. **Entity async computations**: Entity-level computations that generate data for entities
|
|
51
|
+
3. **Relation async computations**: Relation-level computations that generate data for relations
|
|
52
|
+
|
|
53
|
+
## Implementing Global Async Computations
|
|
54
|
+
|
|
55
|
+
### Basic Concepts
|
|
56
|
+
|
|
57
|
+
Global async computations are used to handle system-level data such as global statistics, configuration updates, and external data synchronization.
|
|
58
|
+
|
|
59
|
+
### Creating Global Async Computation Classes
|
|
60
|
+
|
|
61
|
+
```typescript
|
|
62
|
+
import { createClass, ComputationResult } from 'interaqt';
|
|
63
|
+
|
|
64
|
+
// Define global weather computation class
|
|
65
|
+
const GlobalWeatherComputed = createClass({
|
|
66
|
+
name: 'GlobalWeatherComputed',
|
|
67
|
+
public: {
|
|
68
|
+
city: {
|
|
69
|
+
type: 'string',
|
|
70
|
+
required: true
|
|
71
|
+
},
|
|
72
|
+
apiKey: {
|
|
73
|
+
type: 'string',
|
|
74
|
+
required: false
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
// Implement global weather computation
|
|
80
|
+
class GlobalWeatherComputation implements DataBasedComputation {
|
|
81
|
+
static computationType = GlobalWeatherComputed
|
|
82
|
+
static contextType = 'global' as const
|
|
83
|
+
state = {}
|
|
84
|
+
dataDeps: {[key: string]: DataDep} = {}
|
|
85
|
+
|
|
86
|
+
constructor(
|
|
87
|
+
public controller: Controller,
|
|
88
|
+
public args: KlassInstance<typeof GlobalWeatherComputed>,
|
|
89
|
+
public dataContext: GlobalDataContext
|
|
90
|
+
) {
|
|
91
|
+
// Global computations can depend on entity data
|
|
92
|
+
this.dataDeps = {
|
|
93
|
+
// Can depend on data from other entities
|
|
94
|
+
locations: {
|
|
95
|
+
type: 'records',
|
|
96
|
+
source: locationEntity,
|
|
97
|
+
attributeQuery: ['*']
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
async compute(deps: {locations: any[]}) {
|
|
103
|
+
// Return async task with parameters needed for external API call
|
|
104
|
+
return ComputationResult.async({
|
|
105
|
+
city: this.args.city,
|
|
106
|
+
locationCount: deps.locations.length,
|
|
107
|
+
timestamp: Date.now(),
|
|
108
|
+
apiKey: this.args.apiKey
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
async asyncReturn(result: any, args: any) {
|
|
113
|
+
// Process weather data returned from external API
|
|
114
|
+
return {
|
|
115
|
+
city: args.city,
|
|
116
|
+
temperature: result.temperature || 25,
|
|
117
|
+
weather: result.weather || 'sunny',
|
|
118
|
+
humidity: result.humidity || 60,
|
|
119
|
+
lastUpdate: args.timestamp,
|
|
120
|
+
locationCount: args.locationCount
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### Registering Computation Handlers
|
|
127
|
+
|
|
128
|
+
```typescript
|
|
129
|
+
// Export computation handlers
|
|
130
|
+
export const GlobalWeatherHandles = [GlobalWeatherComputation];
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
### Using in Dictionary
|
|
134
|
+
|
|
135
|
+
```typescript
|
|
136
|
+
// Create global weather dictionary item
|
|
137
|
+
const weatherDictionary = Dictionary.create({
|
|
138
|
+
name: 'currentWeather',
|
|
139
|
+
type: 'object',
|
|
140
|
+
collection: false,
|
|
141
|
+
computation: GlobalWeatherComputed.create({
|
|
142
|
+
city: 'Beijing',
|
|
143
|
+
apiKey: process.env.WEATHER_API_KEY
|
|
144
|
+
})
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
// Register in system
|
|
148
|
+
const controller = new Controller({
|
|
149
|
+
system: system,
|
|
150
|
+
entities: entities,
|
|
151
|
+
relations: relations,
|
|
152
|
+
activities: [],
|
|
153
|
+
interactions: [],
|
|
154
|
+
dict: [weatherDictionary], // Dictionary array
|
|
155
|
+
computations: GlobalWeatherHandles // Pass custom computation handlers
|
|
156
|
+
});
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
### Handling Async Tasks
|
|
160
|
+
|
|
161
|
+
```typescript
|
|
162
|
+
// Get async tasks
|
|
163
|
+
const weatherComputation = Array.from(controller.scheduler.computations.values())
|
|
164
|
+
.find(comp => comp.dataContext.type === 'global' &&
|
|
165
|
+
comp.dataContext.id === 'currentWeather') as DataBasedComputation;
|
|
166
|
+
|
|
167
|
+
const taskRecordName = controller.scheduler.getAsyncTaskRecordKey(weatherComputation);
|
|
168
|
+
|
|
169
|
+
// Query pending tasks
|
|
170
|
+
const pendingTasks = await system.storage.find(taskRecordName, undefined, undefined, ['*']);
|
|
171
|
+
|
|
172
|
+
for (const task of pendingTasks) {
|
|
173
|
+
try {
|
|
174
|
+
// Call external weather API
|
|
175
|
+
const weatherData = await fetchWeatherAPI(task.args.city, task.args.apiKey);
|
|
176
|
+
|
|
177
|
+
// Update task status to success
|
|
178
|
+
await system.storage.update(
|
|
179
|
+
taskRecordName,
|
|
180
|
+
MatchExp.atom({key: 'id', value: ['=', task.id]}),
|
|
181
|
+
{
|
|
182
|
+
result: weatherData,
|
|
183
|
+
status: 'success'
|
|
184
|
+
}
|
|
185
|
+
);
|
|
186
|
+
|
|
187
|
+
// Trigger async return processing
|
|
188
|
+
await controller.scheduler.handleAsyncReturn(weatherComputation, {id: task.id});
|
|
189
|
+
|
|
190
|
+
} catch (error) {
|
|
191
|
+
// Handle error cases
|
|
192
|
+
await system.storage.update(
|
|
193
|
+
taskRecordName,
|
|
194
|
+
MatchExp.atom({key: 'id', value: ['=', task.id]}),
|
|
195
|
+
{
|
|
196
|
+
error: error.message,
|
|
197
|
+
status: 'failed'
|
|
198
|
+
}
|
|
199
|
+
);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// Get computation results
|
|
204
|
+
const currentWeather = await system.storage.get('state', 'currentWeather');
|
|
205
|
+
console.log('Current weather:', currentWeather);
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
## Implementing Entity Async Computations
|
|
209
|
+
|
|
210
|
+
### Use Cases
|
|
211
|
+
|
|
212
|
+
Entity async computations are used to generate properties based on external data for entities, such as:
|
|
213
|
+
- Product recommendations
|
|
214
|
+
- User profile analysis
|
|
215
|
+
- Content personalization
|
|
216
|
+
- Risk assessment
|
|
217
|
+
|
|
218
|
+
### Creating Entity Async Computations
|
|
219
|
+
|
|
220
|
+
```typescript
|
|
221
|
+
// Define product recommendation computation class
|
|
222
|
+
const ProductRecommendationComputed = createClass({
|
|
223
|
+
name: 'ProductRecommendationComputed',
|
|
224
|
+
public: {
|
|
225
|
+
algorithm: {
|
|
226
|
+
type: 'string',
|
|
227
|
+
required: true
|
|
228
|
+
},
|
|
229
|
+
maxResults: {
|
|
230
|
+
type: 'number',
|
|
231
|
+
required: false
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
// Implement product recommendation computation
|
|
237
|
+
class ProductRecommendationComputation implements DataBasedComputation {
|
|
238
|
+
static computationType = ProductRecommendationComputed
|
|
239
|
+
static contextType = 'entity' as const
|
|
240
|
+
state = {}
|
|
241
|
+
dataDeps: {[key: string]: DataDep} = {}
|
|
242
|
+
|
|
243
|
+
constructor(
|
|
244
|
+
public controller: Controller,
|
|
245
|
+
public args: KlassInstance<typeof ProductRecommendationComputed>,
|
|
246
|
+
public dataContext: EntityDataContext
|
|
247
|
+
) {
|
|
248
|
+
// Depend on user's purchase history and product data
|
|
249
|
+
this.dataDeps = {
|
|
250
|
+
purchases: {
|
|
251
|
+
type: 'records',
|
|
252
|
+
source: purchaseRelation,
|
|
253
|
+
attributeQuery: ['*']
|
|
254
|
+
},
|
|
255
|
+
products: {
|
|
256
|
+
type: 'records',
|
|
257
|
+
source: productEntity,
|
|
258
|
+
attributeQuery: ['*']
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
async compute(deps: {purchases: any[], products: any[]}) {
|
|
264
|
+
const maxResults = this.args.maxResults || 10;
|
|
265
|
+
|
|
266
|
+
// Return async task parameters
|
|
267
|
+
return ComputationResult.async({
|
|
268
|
+
algorithm: this.args.algorithm,
|
|
269
|
+
purchaseHistory: deps.purchases.map(p => ({
|
|
270
|
+
productId: p.productId,
|
|
271
|
+
rating: p.rating,
|
|
272
|
+
timestamp: p.createdAt
|
|
273
|
+
})),
|
|
274
|
+
availableProducts: deps.products.map(p => ({
|
|
275
|
+
id: p.id,
|
|
276
|
+
category: p.category,
|
|
277
|
+
price: p.price,
|
|
278
|
+
tags: p.tags
|
|
279
|
+
})),
|
|
280
|
+
maxResults: maxResults,
|
|
281
|
+
userId: this.dataContext.recordId
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
async asyncReturn(result: any, args: any) {
|
|
286
|
+
// Process recommendation algorithm results
|
|
287
|
+
return result.recommendations.map((rec: any) => ({
|
|
288
|
+
productId: rec.productId,
|
|
289
|
+
score: rec.score,
|
|
290
|
+
reason: rec.reason,
|
|
291
|
+
algorithm: args.algorithm,
|
|
292
|
+
generatedAt: Date.now()
|
|
293
|
+
}));
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
// Export entity computation handler
|
|
298
|
+
export const ProductRecommendationHandles = [ProductRecommendationComputation];
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
### Using in Entities
|
|
302
|
+
|
|
303
|
+
```typescript
|
|
304
|
+
// Create user entity with recommendation computation
|
|
305
|
+
const userEntity = Entity.create({
|
|
306
|
+
name: 'User',
|
|
307
|
+
properties: [
|
|
308
|
+
Property.create({name: 'username', type: 'string'}),
|
|
309
|
+
Property.create({name: 'email', type: 'string'})
|
|
310
|
+
]
|
|
311
|
+
});
|
|
312
|
+
|
|
313
|
+
// Create recommendation entity
|
|
314
|
+
const recommendationEntity = Entity.create({
|
|
315
|
+
name: 'Recommendation',
|
|
316
|
+
properties: [
|
|
317
|
+
Property.create({name: 'productId', type: 'string'}),
|
|
318
|
+
Property.create({name: 'score', type: 'string'}),
|
|
319
|
+
Property.create({name: 'reason', type: 'string'}),
|
|
320
|
+
Property.create({name: 'algorithm', type: 'string'}),
|
|
321
|
+
Property.create({name: 'generatedAt', type: 'number'})
|
|
322
|
+
],
|
|
323
|
+
computation: ProductRecommendationComputed.create({
|
|
324
|
+
algorithm: 'collaborative_filtering',
|
|
325
|
+
maxResults: 5
|
|
326
|
+
})
|
|
327
|
+
});
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
## Implementing Relation Async Computations
|
|
331
|
+
|
|
332
|
+
### Use Cases
|
|
333
|
+
|
|
334
|
+
Relation async computations are used to generate new relation properties based on relation data, such as:
|
|
335
|
+
- User similarity calculations
|
|
336
|
+
- Relationship strength scoring
|
|
337
|
+
- Social network analysis
|
|
338
|
+
- Collaborative filtering
|
|
339
|
+
|
|
340
|
+
### Creating Relation Async Computations
|
|
341
|
+
|
|
342
|
+
```typescript
|
|
343
|
+
// Define relation similarity computation class
|
|
344
|
+
const RelationSimilarityComputed = createClass({
|
|
345
|
+
name: 'RelationSimilarityComputed',
|
|
346
|
+
public: {
|
|
347
|
+
algorithm: {
|
|
348
|
+
type: 'string',
|
|
349
|
+
required: true
|
|
350
|
+
},
|
|
351
|
+
threshold: {
|
|
352
|
+
type: 'number',
|
|
353
|
+
required: false
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
});
|
|
357
|
+
|
|
358
|
+
// Implement relation similarity computation
|
|
359
|
+
class RelationSimilarityComputation implements DataBasedComputation {
|
|
360
|
+
static computationType = RelationSimilarityComputed
|
|
361
|
+
static contextType = 'relation' as const
|
|
362
|
+
state = {}
|
|
363
|
+
dataDeps: {[key: string]: DataDep} = {}
|
|
364
|
+
|
|
365
|
+
constructor(
|
|
366
|
+
public controller: Controller,
|
|
367
|
+
public args: KlassInstance<typeof RelationSimilarityComputed>,
|
|
368
|
+
public dataContext: RelationDataContext
|
|
369
|
+
) {
|
|
370
|
+
// Depend on relation data and related entity data
|
|
371
|
+
this.dataDeps = {
|
|
372
|
+
relations: {
|
|
373
|
+
type: 'records',
|
|
374
|
+
source: dataContext.id,
|
|
375
|
+
attributeQuery: ['*']
|
|
376
|
+
},
|
|
377
|
+
users: {
|
|
378
|
+
type: 'records',
|
|
379
|
+
source: userEntity,
|
|
380
|
+
attributeQuery: ['*']
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
async compute(deps: {relations: any[], users: any[]}) {
|
|
386
|
+
const threshold = this.args.threshold || 0.5;
|
|
387
|
+
|
|
388
|
+
// Return async task parameters
|
|
389
|
+
return ComputationResult.async({
|
|
390
|
+
algorithm: this.args.algorithm,
|
|
391
|
+
threshold: threshold,
|
|
392
|
+
relationCount: deps.relations.length,
|
|
393
|
+
userCount: deps.users.length,
|
|
394
|
+
timestamp: Date.now()
|
|
395
|
+
});
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
async asyncReturn(result: any, args: any) {
|
|
399
|
+
// Process similarity calculation results
|
|
400
|
+
return result.similarities.map((sim: any) => ({
|
|
401
|
+
userId1: sim.userId1,
|
|
402
|
+
userId2: sim.userId2,
|
|
403
|
+
similarity: sim.score,
|
|
404
|
+
algorithm: args.algorithm,
|
|
405
|
+
computedAt: args.timestamp,
|
|
406
|
+
confidence: sim.confidence
|
|
407
|
+
}));
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
// Export relation computation handler
|
|
412
|
+
export const RelationSimilarityHandles = [RelationSimilarityComputation];
|
|
413
|
+
```
|
|
414
|
+
|
|
415
|
+
## Best Practices for Async Computations
|
|
416
|
+
|
|
417
|
+
### Error Handling
|
|
418
|
+
|
|
419
|
+
```typescript
|
|
420
|
+
class RobustAsyncComputation implements DataBasedComputation {
|
|
421
|
+
async compute(deps: any) {
|
|
422
|
+
try {
|
|
423
|
+
// Validate input parameters
|
|
424
|
+
if (!this.validateInput(deps)) {
|
|
425
|
+
throw new Error('Invalid input parameters');
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
return ComputationResult.async({
|
|
429
|
+
...deps,
|
|
430
|
+
retryCount: 0,
|
|
431
|
+
timeout: 30000
|
|
432
|
+
});
|
|
433
|
+
} catch (error) {
|
|
434
|
+
// Log errors
|
|
435
|
+
console.error('Computation failed:', error);
|
|
436
|
+
throw error;
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
async asyncReturn(result: any, args: any) {
|
|
441
|
+
try {
|
|
442
|
+
// Validate return results
|
|
443
|
+
if (!this.validateResult(result)) {
|
|
444
|
+
throw new Error('Invalid async result');
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
return this.processResult(result, args);
|
|
448
|
+
} catch (error) {
|
|
449
|
+
// Error recovery mechanism
|
|
450
|
+
return this.getDefaultResult(args);
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
private validateInput(deps: any): boolean {
|
|
455
|
+
// Input validation logic
|
|
456
|
+
return deps && typeof deps === 'object';
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
private validateResult(result: any): boolean {
|
|
460
|
+
// Result validation logic
|
|
461
|
+
return result && result.status === 'success';
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
private getDefaultResult(args: any): any {
|
|
465
|
+
// Return default result
|
|
466
|
+
return { error: 'Computation failed, using default values' };
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
```
|
|
470
|
+
|
|
471
|
+
### Performance Optimization
|
|
472
|
+
|
|
473
|
+
```typescript
|
|
474
|
+
class OptimizedAsyncComputation implements DataBasedComputation {
|
|
475
|
+
private cache = new Map<string, any>();
|
|
476
|
+
|
|
477
|
+
async compute(deps: any) {
|
|
478
|
+
// Generate cache key
|
|
479
|
+
const cacheKey = this.generateCacheKey(deps);
|
|
480
|
+
|
|
481
|
+
// Check cache
|
|
482
|
+
if (this.cache.has(cacheKey)) {
|
|
483
|
+
const cachedResult = this.cache.get(cacheKey);
|
|
484
|
+
if (this.isCacheValid(cachedResult)) {
|
|
485
|
+
return cachedResult;
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
// Batch process multiple tasks
|
|
490
|
+
const batchSize = 10;
|
|
491
|
+
const batches = this.createBatches(deps, batchSize);
|
|
492
|
+
|
|
493
|
+
return ComputationResult.async({
|
|
494
|
+
batches,
|
|
495
|
+
cacheKey,
|
|
496
|
+
timestamp: Date.now()
|
|
497
|
+
});
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
async asyncReturn(result: any, args: any) {
|
|
501
|
+
// Process batch results
|
|
502
|
+
const processedResults = [];
|
|
503
|
+
|
|
504
|
+
for (const batch of result.batches) {
|
|
505
|
+
const batchResult = await this.processBatch(batch);
|
|
506
|
+
processedResults.push(...batchResult);
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
// Update cache
|
|
510
|
+
this.cache.set(args.cacheKey, {
|
|
511
|
+
data: processedResults,
|
|
512
|
+
timestamp: args.timestamp,
|
|
513
|
+
ttl: 3600000 // 1 hour
|
|
514
|
+
});
|
|
515
|
+
|
|
516
|
+
return processedResults;
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
private generateCacheKey(deps: any): string {
|
|
520
|
+
return JSON.stringify(deps);
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
private isCacheValid(cachedResult: any): boolean {
|
|
524
|
+
const now = Date.now();
|
|
525
|
+
return (now - cachedResult.timestamp) < cachedResult.ttl;
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
private createBatches(deps: any, batchSize: number): any[] {
|
|
529
|
+
// Create batch logic
|
|
530
|
+
const items = deps.items || [];
|
|
531
|
+
const batches = [];
|
|
532
|
+
|
|
533
|
+
for (let i = 0; i < items.length; i += batchSize) {
|
|
534
|
+
batches.push(items.slice(i, i + batchSize));
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
return batches;
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
private async processBatch(batch: any[]): Promise<any[]> {
|
|
541
|
+
// Batch processing logic
|
|
542
|
+
return Promise.all(batch.map(item => this.processItem(item)));
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
private async processItem(item: any): Promise<any> {
|
|
546
|
+
// Single item processing logic
|
|
547
|
+
return { ...item, processed: true };
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
```
|
|
551
|
+
|
|
552
|
+
### Monitoring and Debugging
|
|
553
|
+
|
|
554
|
+
```typescript
|
|
555
|
+
class MonitoredAsyncComputation implements DataBasedComputation {
|
|
556
|
+
private metrics = {
|
|
557
|
+
computeCount: 0,
|
|
558
|
+
asyncReturnCount: 0,
|
|
559
|
+
errorCount: 0,
|
|
560
|
+
totalDuration: 0
|
|
561
|
+
};
|
|
562
|
+
|
|
563
|
+
async compute(deps: any) {
|
|
564
|
+
const startTime = Date.now();
|
|
565
|
+
this.metrics.computeCount++;
|
|
566
|
+
|
|
567
|
+
try {
|
|
568
|
+
const result = await this.performCompute(deps);
|
|
569
|
+
|
|
570
|
+
// Record performance metrics
|
|
571
|
+
const duration = Date.now() - startTime;
|
|
572
|
+
this.metrics.totalDuration += duration;
|
|
573
|
+
|
|
574
|
+
console.log(`Compute completed in ${duration}ms`);
|
|
575
|
+
|
|
576
|
+
return result;
|
|
577
|
+
} catch (error) {
|
|
578
|
+
this.metrics.errorCount++;
|
|
579
|
+
console.error('Compute error:', error);
|
|
580
|
+
throw error;
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
async asyncReturn(result: any, args: any) {
|
|
585
|
+
const startTime = Date.now();
|
|
586
|
+
this.metrics.asyncReturnCount++;
|
|
587
|
+
|
|
588
|
+
try {
|
|
589
|
+
const processedResult = await this.performAsyncReturn(result, args);
|
|
590
|
+
|
|
591
|
+
const duration = Date.now() - startTime;
|
|
592
|
+
console.log(`AsyncReturn completed in ${duration}ms`);
|
|
593
|
+
|
|
594
|
+
return processedResult;
|
|
595
|
+
} catch (error) {
|
|
596
|
+
this.metrics.errorCount++;
|
|
597
|
+
console.error('AsyncReturn error:', error);
|
|
598
|
+
throw error;
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
getMetrics() {
|
|
603
|
+
return {
|
|
604
|
+
...this.metrics,
|
|
605
|
+
averageDuration: this.metrics.totalDuration / this.metrics.computeCount,
|
|
606
|
+
errorRate: this.metrics.errorCount / (this.metrics.computeCount + this.metrics.asyncReturnCount)
|
|
607
|
+
};
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
private async performCompute(deps: any) {
|
|
611
|
+
// Actual computation logic
|
|
612
|
+
return ComputationResult.async(deps);
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
private async performAsyncReturn(result: any, args: any) {
|
|
616
|
+
// Actual async return processing logic
|
|
617
|
+
return result;
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
```
|
|
621
|
+
|
|
622
|
+
## Complete Example: Intelligent Recommendation System
|
|
623
|
+
|
|
624
|
+
Here's a complete intelligent recommendation system example showing how to comprehensively use global, entity, and relation async computations:
|
|
625
|
+
|
|
626
|
+
```typescript
|
|
627
|
+
// 1. Define entities
|
|
628
|
+
const userEntity = Entity.create({
|
|
629
|
+
name: 'User',
|
|
630
|
+
properties: [
|
|
631
|
+
Property.create({name: 'username', type: 'string'}),
|
|
632
|
+
Property.create({name: 'preferences', type: 'object'})
|
|
633
|
+
]
|
|
634
|
+
});
|
|
635
|
+
|
|
636
|
+
const productEntity = Entity.create({
|
|
637
|
+
name: 'Product',
|
|
638
|
+
properties: [
|
|
639
|
+
Property.create({name: 'name', type: 'string'}),
|
|
640
|
+
Property.create({name: 'category', type: 'string'}),
|
|
641
|
+
Property.create({name: 'price', type: 'number'}),
|
|
642
|
+
Property.create({name: 'features', type: 'object'})
|
|
643
|
+
]
|
|
644
|
+
});
|
|
645
|
+
|
|
646
|
+
// 2. Define relations
|
|
647
|
+
const purchaseRelation = Relation.create({
|
|
648
|
+
name: 'Purchase',
|
|
649
|
+
source: userEntity,
|
|
650
|
+
sourceProperty: 'purchases',
|
|
651
|
+
target: productEntity,
|
|
652
|
+
targetProperty: 'buyers',
|
|
653
|
+
type: 'n:n',
|
|
654
|
+
properties: [
|
|
655
|
+
Property.create({name: 'rating', type: 'number'}),
|
|
656
|
+
Property.create({name: 'review', type: 'string'}),
|
|
657
|
+
Property.create({name: 'purchaseDate', type: 'string'})
|
|
658
|
+
]
|
|
659
|
+
});
|
|
660
|
+
|
|
661
|
+
// 3. Async task scheduler
|
|
662
|
+
class AsyncTaskScheduler {
|
|
663
|
+
constructor(private controller: Controller, private system: MonoSystem) {}
|
|
664
|
+
|
|
665
|
+
async processAllAsyncTasks() {
|
|
666
|
+
const computations = Array.from(this.controller.scheduler.computations.values());
|
|
667
|
+
|
|
668
|
+
for (const computation of computations) {
|
|
669
|
+
await this.processComputationTasks(computation as DataBasedComputation);
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
private async processComputationTasks(computation: DataBasedComputation) {
|
|
674
|
+
const taskRecordName = this.controller.scheduler.getAsyncTaskRecordKey(computation);
|
|
675
|
+
const tasks = await this.system.storage.find(taskRecordName, undefined, undefined, ['*']);
|
|
676
|
+
|
|
677
|
+
for (const task of tasks) {
|
|
678
|
+
try {
|
|
679
|
+
let result;
|
|
680
|
+
|
|
681
|
+
// Call different processing services based on computation type
|
|
682
|
+
if (computation.dataContext.type === 'global') {
|
|
683
|
+
result = await this.processGlobalTask(task);
|
|
684
|
+
} else if (computation.dataContext.type === 'entity') {
|
|
685
|
+
result = await this.processEntityTask(task);
|
|
686
|
+
} else if (computation.dataContext.type === 'relation') {
|
|
687
|
+
result = await this.processRelationTask(task);
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
// Update task status
|
|
691
|
+
await this.system.storage.update(
|
|
692
|
+
taskRecordName,
|
|
693
|
+
MatchExp.atom({key: 'id', value: ['=', task.id]}),
|
|
694
|
+
{ result, status: 'success' }
|
|
695
|
+
);
|
|
696
|
+
|
|
697
|
+
// Process async return
|
|
698
|
+
await this.controller.scheduler.handleAsyncReturn(computation, {id: task.id});
|
|
699
|
+
|
|
700
|
+
} catch (error) {
|
|
701
|
+
console.error(`Task processing failed:`, error);
|
|
702
|
+
await this.system.storage.update(
|
|
703
|
+
taskRecordName,
|
|
704
|
+
MatchExp.atom({key: 'id', value: ['=', task.id]}),
|
|
705
|
+
{ error: error.message, status: 'failed' }
|
|
706
|
+
);
|
|
707
|
+
}
|
|
708
|
+
}
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
private async processGlobalTask(task: any) {
|
|
712
|
+
// Process global tasks
|
|
713
|
+
return await callTrendAnalysisAPI(task.args);
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
private async processEntityTask(task: any) {
|
|
717
|
+
// Process entity tasks
|
|
718
|
+
return await callRecommendationAPI(task.args);
|
|
719
|
+
}
|
|
720
|
+
|
|
721
|
+
private async processRelationTask(task: any) {
|
|
722
|
+
// Process relation tasks
|
|
723
|
+
return await callSimilarityAPI(task.args);
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
// 4. Start async task processing
|
|
728
|
+
const scheduler = new AsyncTaskScheduler(controller, system);
|
|
729
|
+
setInterval(() => {
|
|
730
|
+
scheduler.processAllAsyncTasks().catch(console.error);
|
|
731
|
+
}, 5000); // Process async tasks every 5 seconds
|
|
732
|
+
```
|
|
733
|
+
|
|
734
|
+
Async computations provide the interaqt framework with powerful extension capabilities, enabling the system to handle complex business logic and external integration requirements. Through proper use of async computations, you can build feature-rich, high-performance reactive application systems.
|