0
# Manager Operations
1
2
The ManagerClient provides advanced operations for multi-hub environments including hub management, distributed store operations, and cross-hub monitoring.
3
4
## Capabilities
5
6
### Manager Client Creation
7
8
Create a ManagerClient for advanced Hub management operations.
9
10
```typescript { .api }
11
/**
12
* Creates a new ManagerClient instance for advanced Hub management
13
* @param apiBase - Base URL for the Manager API (e.g., "http://localhost:8001/api/v1")
14
* @param utils - Optional custom ClientUtils instance for advanced configuration
15
*/
16
class ManagerClient implements ClientProvider {
17
constructor(apiBase: string, utils?: ClientUtils);
18
19
readonly apiBase: string;
20
readonly client: ClientUtils;
21
}
22
```
23
24
**Usage Example:**
25
26
```typescript
27
import { ManagerClient } from "@scramjet/api-client";
28
29
const manager = new ManagerClient("http://localhost:8001/api/v1");
30
```
31
32
### Hub Management
33
34
Manage multiple Transform Hub instances in a distributed environment.
35
36
```typescript { .api }
37
/**
38
* Gets information about all connected Hubs
39
* @returns Promise resolving to array of Hub information
40
*/
41
getHosts(): Promise<MRestAPI.GetHostInfoResponse[]>;
42
43
/**
44
* Creates a HostClient for a specific Hub
45
* @param id - Hub identifier
46
* @param hostApiBase - Optional API base path for the Hub (defaults to "/api/v1")
47
* @returns HostClient instance configured for the specified Hub
48
*/
49
getHostClient(id: string, hostApiBase?: string): HostClient;
50
51
/**
52
* Deletes a Hub from the Manager
53
* @param id - Hub identifier
54
* @param force - Whether to force deletion even if Hub has running instances
55
* @returns Promise resolving to deletion result
56
*/
57
deleteHub(id: string, force: boolean): Promise<MRestAPI.HubDeleteResponse>;
58
59
/**
60
* Disconnects Hubs based on specified criteria
61
* @param opts - Disconnection options and criteria
62
* @returns Promise resolving to disconnection results
63
*/
64
disconnectHubs(opts: MRestAPI.PostDisconnectPayload): Promise<MRestAPI.PostDisconnectResponse>;
65
```
66
67
**Usage Examples:**
68
69
```typescript
70
// List all connected Hubs
71
const hubs = await manager.getHosts();
72
console.log(`Connected to ${hubs.length} Hubs:`);
73
hubs.forEach(hub => {
74
console.log(`- ${hub.id}: ${hub.address} (${hub.status})`);
75
});
76
77
// Get a client for a specific Hub
78
const specificHub = manager.getHostClient("hub-001");
79
const sequences = await specificHub.listSequences();
80
81
// Remove a disconnected Hub
82
await manager.deleteHub("hub-002", true);
83
```
84
85
### Cross-Hub Operations
86
87
Query and manage resources across all connected Hubs.
88
89
```typescript { .api }
90
/**
91
* Gets all sequences across all connected Hubs
92
* @returns Promise resolving to comprehensive sequence list
93
*/
94
getAllSequences(): Promise<MRestAPI.GetSequencesResponse>;
95
96
/**
97
* Gets sequences from the Manager's perspective
98
* @returns Promise resolving to Manager-tracked sequences
99
*/
100
getSequences(): Promise<MRestAPI.GetSequencesResponse>;
101
102
/**
103
* Gets all instances across all connected Hubs
104
* @returns Promise resolving to comprehensive instance list
105
*/
106
getInstances(): Promise<MRestAPI.GetInstancesResponse>;
107
108
/**
109
* Gets all topics across all connected Hubs
110
* @returns Promise resolving to comprehensive topics list
111
*/
112
getTopics(): Promise<MRestAPI.GetTopicsResponse>;
113
```
114
115
**Usage Examples:**
116
117
```typescript
118
// Get global view of all resources
119
const allSequences = await manager.getAllSequences();
120
console.log(`Total sequences across all Hubs: ${allSequences.length}`);
121
122
const allInstances = await manager.getInstances();
123
const runningInstances = allInstances.filter(i => i.status === "running");
124
console.log(`Running instances: ${runningInstances.length}/${allInstances.length}`);
125
126
// Find instances by sequence name across all Hubs
127
const targetSequences = allSequences.filter(s => s.config.name === "data-processor");
128
for (const seq of targetSequences) {
129
console.log(`Hub ${seq.hubId}: sequence ${seq.id} has ${seq.instances.length} instances`);
130
}
131
```
132
133
### Distributed Store Operations
134
135
Manage shared storage across the Hub network.
136
137
```typescript { .api }
138
/**
139
* Gets all items from the distributed store
140
* @returns Promise resolving to store items list
141
*/
142
getStoreItems(): Promise<MRestAPI.GetStoreItemsResponse>;
143
144
/**
145
* Uploads an item to the distributed store
146
* @param sequencePackage - Stream containing the data to store
147
* @param id - Optional identifier for the stored item
148
* @returns Promise resolving to store operation result
149
*/
150
putStoreItem(
151
sequencePackage: Readable,
152
id?: string
153
): Promise<MRestAPI.PutStoreItemResponse>;
154
155
/**
156
* Deletes an item from the distributed store
157
* @param id - Identifier of the item to delete
158
* @returns Promise resolving when deletion is complete
159
*/
160
deleteStoreItem(id: string): Promise<void>;
161
162
/**
163
* Clears all items from the distributed store
164
* @returns Promise resolving when store is cleared
165
*/
166
clearStore(): Promise<void>;
167
```
168
169
**Usage Examples:**
170
171
```typescript
172
import fs from "fs";
173
174
// Upload a sequence package to shared store
175
const packageStream = fs.createReadStream("./shared-utility.tar.gz");
176
const storeResult = await manager.putStoreItem(packageStream, "shared-utility-v1.0");
177
console.log(`Stored item: ${storeResult.id}`);
178
179
// List all stored items
180
const storeItems = await manager.getStoreItems();
181
storeItems.forEach(item => {
182
console.log(`- ${item.id}: ${item.size} bytes, uploaded ${item.created}`);
183
});
184
185
// Clean up old items
186
const oldItems = storeItems.filter(item =>
187
new Date(item.created) < new Date(Date.now() - 30 * 24 * 60 * 60 * 1000) // 30 days
188
);
189
for (const item of oldItems) {
190
await manager.deleteStoreItem(item.id);
191
console.log(`Removed old item: ${item.id}`);
192
}
193
```
194
195
### System Monitoring
196
197
Monitor system-wide metrics and health across all Hubs.
198
199
```typescript { .api }
200
/**
201
* Gets Manager version information
202
* @returns Promise resolving to version details
203
*/
204
getVersion(): Promise<MRestAPI.GetVersionResponse>;
205
206
/**
207
* Gets aggregate load statistics across all Hubs
208
* @returns Promise resolving to load statistics
209
*/
210
getLoad(): Promise<LoadCheckStat>;
211
212
/**
213
* Gets Manager configuration
214
* @returns Promise resolving to configuration data
215
*/
216
getConfig(): Promise<any>;
217
```
218
219
### Streaming Operations
220
221
Access aggregated log and audit streams from all Hubs.
222
223
```typescript { .api }
224
/**
225
* Gets aggregated log stream from all connected Hubs
226
* @param requestInit - Optional request configuration
227
* @returns Promise resolving to aggregated log stream
228
*/
229
getLogStream(requestInit?: RequestInit): Promise<Readable>;
230
231
/**
232
* Gets aggregated audit stream from all connected Hubs
233
* @param requestInit - Optional request configuration
234
* @returns Promise resolving to aggregated audit stream
235
*/
236
getAuditStream(requestInit?: RequestInit): Promise<Readable>;
237
238
/**
239
* Sends data to a named topic across the Hub network
240
* @param topic - Topic name
241
* @param stream - Data stream to send
242
* @param requestInit - Optional request configuration
243
* @param contentType - Content type
244
* @param end - Whether to signal end of stream
245
* @returns Promise resolving to send result
246
*/
247
sendNamedData<T>(
248
topic: string,
249
stream: Parameters<HttpClient["sendStream"]>[1],
250
requestInit?: RequestInit,
251
contentType?: string,
252
end?: boolean
253
): Promise<T>;
254
255
/**
256
* Gets data stream from a named topic across the Hub network
257
* @param topic - Topic name
258
* @param requestInit - Optional request configuration
259
* @returns Promise resolving to topic data stream
260
*/
261
getNamedData(topic: string, requestInit?: RequestInit): Promise<Readable>;
262
```
263
264
**Usage Examples:**
265
266
```typescript
267
// Monitor aggregate system logs
268
const logStream = await manager.getLogStream();
269
logStream.on('data', (chunk) => {
270
const logEntry = JSON.parse(chunk.toString());
271
console.log(`[${logEntry.hubId}] ${logEntry.level}: ${logEntry.message}`);
272
});
273
274
// Broadcast configuration updates
275
const configStream = Readable.from([JSON.stringify({
276
action: "update-config",
277
config: { logLevel: "debug" }
278
})]);
279
await manager.sendNamedData("system-config", configStream);
280
```
281
282
## Response Types
283
284
```typescript { .api }
285
interface MRestAPI {
286
GetHostInfoResponse: {
287
id: string;
288
address: string;
289
status: "connected" | "disconnected" | "error";
290
version: string;
291
load: {
292
avgLoad: number[];
293
currentLoad: number;
294
memUsage: number;
295
};
296
sequences: number;
297
instances: number;
298
uptime: number;
299
[key: string]: any;
300
};
301
302
GetSequencesResponse: Array<{
303
id: string;
304
hubId: string;
305
config: {
306
name: string;
307
version: string;
308
[key: string]: any;
309
};
310
instances: string[];
311
}>;
312
313
GetInstancesResponse: Array<{
314
id: string;
315
hubId: string;
316
sequenceId: string;
317
status: "starting" | "running" | "stopping" | "stopped" | "crashed";
318
created: string;
319
[key: string]: any;
320
}>;
321
322
GetTopicsResponse: Array<{
323
id: string;
324
hubId: string;
325
contentType: string;
326
subscribers: number;
327
[key: string]: any;
328
}>;
329
330
GetStoreItemsResponse: Array<{
331
id: string;
332
size: number;
333
created: string;
334
checksum: string;
335
[key: string]: any;
336
}>;
337
338
PutStoreItemResponse: {
339
id: string;
340
size: number;
341
checksum: string;
342
};
343
344
HubDeleteResponse: {
345
id: string;
346
message: string;
347
deleted: boolean;
348
};
349
350
PostDisconnectPayload: {
351
criteria: {
352
status?: "disconnected" | "error";
353
olderThan?: string; // ISO date string
354
hubIds?: string[];
355
};
356
force?: boolean;
357
};
358
359
PostDisconnectResponse: {
360
disconnected: string[];
361
errors: Array<{
362
hubId: string;
363
error: string;
364
}>;
365
};
366
367
GetVersionResponse: {
368
version: string;
369
build?: string;
370
components: {
371
[componentName: string]: string;
372
};
373
};
374
}
375
```
376
377
## Advanced Patterns
378
379
### Multi-Hub Deployment Management
380
381
```typescript
382
class MultiHubDeployment {
383
constructor(private manager: ManagerClient) {}
384
385
async deployToAllHubs(packagePath: string, config: any) {
386
const hubs = await this.manager.getHosts();
387
const deployments = [];
388
389
for (const hub of hubs.filter(h => h.status === "connected")) {
390
try {
391
const hostClient = this.manager.getHostClient(hub.id);
392
const packageStream = fs.createReadStream(packagePath);
393
const sequence = await hostClient.sendSequence(packageStream);
394
const instance = await sequence.start(config);
395
396
deployments.push({
397
hubId: hub.id,
398
sequenceId: sequence.id,
399
instanceId: instance.id
400
});
401
} catch (error) {
402
console.error(`Failed to deploy to hub ${hub.id}:`, error.message);
403
}
404
}
405
406
return deployments;
407
}
408
409
async scaleAcrossHubs(sequenceName: string, targetInstances: number) {
410
const sequences = await this.manager.getAllSequences();
411
const targetSequences = sequences.filter(s => s.config.name === sequenceName);
412
413
for (const seq of targetSequences) {
414
const currentInstances = seq.instances.length;
415
const needed = Math.max(0, targetInstances - currentInstances);
416
417
if (needed > 0) {
418
const hubClient = this.manager.getHostClient(seq.hubId);
419
const sequenceClient = hubClient.getSequenceClient(seq.id);
420
421
for (let i = 0; i < needed; i++) {
422
await sequenceClient.start({});
423
}
424
}
425
}
426
}
427
}
428
```
429
430
### Distributed Load Monitoring
431
432
```typescript
433
async function monitorClusterHealth(manager: ManagerClient) {
434
const hubs = await manager.getHosts();
435
const aggregateLoad = await manager.getLoad();
436
437
console.log(`Cluster Overview:`);
438
console.log(`- Total Hubs: ${hubs.length}`);
439
console.log(`- Aggregate Load: ${aggregateLoad.currentLoad.toFixed(2)}`);
440
console.log(`- Memory Usage: ${aggregateLoad.memUsage.toFixed(1)}%`);
441
442
// Check for overloaded hubs
443
const overloadedHubs = hubs.filter(hub => hub.load.currentLoad > 0.8);
444
if (overloadedHubs.length > 0) {
445
console.log(`⚠️ Overloaded Hubs (>80% CPU):`);
446
overloadedHubs.forEach(hub => {
447
console.log(` - ${hub.id}: ${(hub.load.currentLoad * 100).toFixed(1)}% CPU`);
448
});
449
}
450
451
// Check for disconnected hubs
452
const disconnectedHubs = hubs.filter(hub => hub.status !== "connected");
453
if (disconnectedHubs.length > 0) {
454
console.log(`❌ Disconnected Hubs:`);
455
disconnectedHubs.forEach(hub => {
456
console.log(` - ${hub.id}: ${hub.status}`);
457
});
458
}
459
}
460
```