@gravito/zenith 1.1.2 → 1.1.6

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.
Files changed (76) hide show
  1. package/README.md +95 -22
  2. package/README.zh-TW.md +88 -0
  3. package/dist/bin.js +54699 -39316
  4. package/dist/client/assets/index-C80c1frR.css +1 -0
  5. package/dist/client/assets/index-CrWem9u3.js +434 -0
  6. package/dist/client/index.html +2 -2
  7. package/dist/server/index.js +54699 -39316
  8. package/package.json +20 -9
  9. package/CHANGELOG.md +0 -47
  10. package/Dockerfile +0 -46
  11. package/Dockerfile.demo-worker +0 -29
  12. package/ECOSYSTEM_EXPANSION_RFC.md +0 -130
  13. package/bin/flux-console.ts +0 -2
  14. package/dist/client/assets/index-BSMp8oq_.js +0 -436
  15. package/dist/client/assets/index-BwxlHx-_.css +0 -1
  16. package/docker-compose.yml +0 -40
  17. package/docs/ALERTING_GUIDE.md +0 -71
  18. package/docs/DEPLOYMENT.md +0 -157
  19. package/docs/DOCS_INTERNAL.md +0 -73
  20. package/docs/LARAVEL_ZENITH_ROADMAP.md +0 -109
  21. package/docs/QUASAR_MASTER_PLAN.md +0 -140
  22. package/docs/QUICK_TEST_GUIDE.md +0 -72
  23. package/docs/ROADMAP.md +0 -85
  24. package/docs/integrations/LARAVEL.md +0 -207
  25. package/postcss.config.js +0 -6
  26. package/scripts/debug_redis_keys.ts +0 -24
  27. package/scripts/flood-logs.ts +0 -21
  28. package/scripts/seed.ts +0 -213
  29. package/scripts/verify-throttle.ts +0 -49
  30. package/scripts/worker.ts +0 -124
  31. package/specs/PULSE_SPEC.md +0 -86
  32. package/src/bin.ts +0 -6
  33. package/src/client/App.tsx +0 -72
  34. package/src/client/Layout.tsx +0 -672
  35. package/src/client/Sidebar.tsx +0 -112
  36. package/src/client/ThroughputChart.tsx +0 -144
  37. package/src/client/WorkerStatus.tsx +0 -226
  38. package/src/client/components/BrandIcons.tsx +0 -168
  39. package/src/client/components/ConfirmDialog.tsx +0 -126
  40. package/src/client/components/JobInspector.tsx +0 -554
  41. package/src/client/components/LogArchiveModal.tsx +0 -432
  42. package/src/client/components/NotificationBell.tsx +0 -212
  43. package/src/client/components/PageHeader.tsx +0 -47
  44. package/src/client/components/Toaster.tsx +0 -90
  45. package/src/client/components/UserProfileDropdown.tsx +0 -186
  46. package/src/client/contexts/AuthContext.tsx +0 -105
  47. package/src/client/contexts/NotificationContext.tsx +0 -128
  48. package/src/client/index.css +0 -174
  49. package/src/client/index.html +0 -12
  50. package/src/client/main.tsx +0 -15
  51. package/src/client/pages/LoginPage.tsx +0 -162
  52. package/src/client/pages/MetricsPage.tsx +0 -417
  53. package/src/client/pages/OverviewPage.tsx +0 -517
  54. package/src/client/pages/PulsePage.tsx +0 -488
  55. package/src/client/pages/QueuesPage.tsx +0 -379
  56. package/src/client/pages/SchedulesPage.tsx +0 -540
  57. package/src/client/pages/SettingsPage.tsx +0 -1020
  58. package/src/client/pages/WorkersPage.tsx +0 -394
  59. package/src/client/pages/index.ts +0 -8
  60. package/src/client/utils.ts +0 -15
  61. package/src/server/config/ServerConfigManager.ts +0 -90
  62. package/src/server/index.ts +0 -860
  63. package/src/server/middleware/auth.ts +0 -127
  64. package/src/server/services/AlertService.ts +0 -321
  65. package/src/server/services/CommandService.ts +0 -137
  66. package/src/server/services/LogStreamProcessor.ts +0 -93
  67. package/src/server/services/MaintenanceScheduler.ts +0 -78
  68. package/src/server/services/PulseService.ts +0 -91
  69. package/src/server/services/QueueMetricsCollector.ts +0 -138
  70. package/src/server/services/QueueService.ts +0 -631
  71. package/src/shared/types.ts +0 -198
  72. package/tailwind.config.js +0 -73
  73. package/tests/placeholder.test.ts +0 -7
  74. package/tsconfig.json +0 -38
  75. package/tsconfig.node.json +0 -12
  76. package/vite.config.ts +0 -27
@@ -1,631 +0,0 @@
1
- import { EventEmitter } from 'node:events'
2
- import { type MySQLPersistence, QueueManager } from '@gravito/stream'
3
- import { Redis } from 'ioredis'
4
- import { AlertService } from './AlertService'
5
- import { LogStreamProcessor } from './LogStreamProcessor'
6
- import { MaintenanceScheduler } from './MaintenanceScheduler'
7
- import { QueueMetricsCollector } from './QueueMetricsCollector'
8
-
9
- export interface QueueStats {
10
- name: string
11
- waiting: number
12
- delayed: number
13
- failed: number
14
- active: number
15
- paused: boolean
16
- }
17
-
18
- export interface WorkerReport {
19
- id: string
20
- hostname: string
21
- pid: number
22
- uptime: number
23
- memory: {
24
- rss: string
25
- heapTotal: string
26
- heapUsed: string
27
- }
28
- queues: string[]
29
- concurrency: number
30
- timestamp: string
31
- loadAvg: number[]
32
- }
33
-
34
- export interface SystemLog {
35
- level: 'info' | 'warn' | 'error' | 'success'
36
- message: string
37
- workerId: string
38
- queue?: string
39
- timestamp: string
40
- }
41
-
42
- export interface GlobalStats {
43
- queues: QueueStats[]
44
- throughput: { timestamp: string; count: number }[]
45
- workers: WorkerReport[]
46
- }
47
-
48
- export class QueueService {
49
- private redis: Redis
50
- private subRedis: Redis
51
- private prefix: string
52
- private logEmitter = new EventEmitter()
53
- private manager: QueueManager
54
- public alerts: AlertService
55
- private logProcessor: LogStreamProcessor
56
- private metricsCollector: QueueMetricsCollector
57
- private maintenanceScheduler: MaintenanceScheduler
58
-
59
- constructor(
60
- redisUrl: string,
61
- prefix = 'queue:',
62
- persistence?: {
63
- adapter: MySQLPersistence
64
- archiveCompleted?: boolean
65
- archiveFailed?: boolean
66
- archiveEnqueued?: boolean
67
- }
68
- ) {
69
- this.redis = new Redis(redisUrl, {
70
- lazyConnect: true,
71
- })
72
- this.subRedis = new Redis(redisUrl, {
73
- lazyConnect: true,
74
- })
75
- this.prefix = prefix
76
- this.logEmitter.setMaxListeners(1000)
77
-
78
- this.logProcessor = new LogStreamProcessor(this.redis, this.subRedis)
79
- this.metricsCollector = new QueueMetricsCollector(this.redis, prefix)
80
- this.maintenanceScheduler = new MaintenanceScheduler(this.redis, (days) =>
81
- this.cleanupArchive(days)
82
- )
83
-
84
- this.manager = new QueueManager({
85
- default: 'redis',
86
- connections: {
87
- redis: {
88
- driver: 'redis',
89
- client: this.redis as any,
90
- prefix,
91
- },
92
- },
93
- persistence,
94
- })
95
- this.alerts = new AlertService(redisUrl)
96
- }
97
-
98
- async connect() {
99
- await Promise.all([
100
- this.redis.connect(),
101
- this.subRedis.connect(),
102
- this.alerts.connect(),
103
- this.logProcessor.subscribe(),
104
- ])
105
-
106
- this.maintenanceScheduler.start(30000)
107
- }
108
-
109
- onLog(callback: (msg: SystemLog) => void): () => void {
110
- const unsub = this.logProcessor.onLog(callback)
111
- const emitterUnsub = () => {
112
- this.logEmitter.off('log', callback)
113
- }
114
- return () => {
115
- unsub()
116
- emitterUnsub()
117
- }
118
- }
119
-
120
- async listQueues(): Promise<QueueStats[]> {
121
- return this.metricsCollector.listQueues()
122
- }
123
-
124
- async pauseQueue(queueName: string): Promise<boolean> {
125
- await this.redis.set(`${this.prefix}${queueName}:paused`, '1')
126
- return true
127
- }
128
-
129
- async resumeQueue(queueName: string): Promise<boolean> {
130
- await this.redis.del(`${this.prefix}${queueName}:paused`)
131
- return true
132
- }
133
-
134
- async isQueuePaused(queueName: string): Promise<boolean> {
135
- const paused = await this.redis.get(`${this.prefix}${queueName}:paused`)
136
- return paused === '1'
137
- }
138
-
139
- async retryDelayedJob(queueName: string): Promise<number> {
140
- const key = `${this.prefix}${queueName}`
141
- const delayKey = `${key}:delayed`
142
-
143
- const script = `
144
- local delayKey = KEYS[1]
145
- local queueKey = KEYS[2]
146
-
147
- local jobs = redis.call('ZRANGE', delayKey, 0, -1)
148
-
149
- if #jobs > 0 then
150
- redis.call('LPUSH', queueKey, unpack(jobs))
151
- redis.call('DEL', delayKey)
152
- end
153
- return #jobs
154
- `
155
-
156
- const movedCount = (await this.redis.eval(script, 2, delayKey, key)) as number
157
- return movedCount
158
- }
159
-
160
- async getJobs(
161
- queueName: string,
162
- type: 'waiting' | 'delayed' | 'failed' = 'waiting',
163
- start = 0,
164
- stop = 49
165
- ): Promise<any[]> {
166
- const key = `${this.prefix}${queueName}`
167
- let rawJobs: string[] = []
168
-
169
- if (type === 'delayed') {
170
- const results = await this.redis.zrange(`${key}:delayed`, start, stop, 'WITHSCORES')
171
- const formatted = []
172
- for (let i = 0; i < results.length; i += 2) {
173
- const jobStr = results[i]!
174
- const score = results[i + 1]!
175
- try {
176
- const parsed = JSON.parse(jobStr)
177
- formatted.push({
178
- ...parsed,
179
- _raw: jobStr,
180
- scheduledAt: new Date(parseInt(score, 10)).toISOString(),
181
- })
182
- } catch (_e) {
183
- formatted.push({ _raw: jobStr, _error: 'Failed to parse JSON' })
184
- }
185
- }
186
- return formatted
187
- } else {
188
- const listKey = type === 'failed' ? `${key}:failed` : key
189
- rawJobs = await this.redis.lrange(listKey, start, stop)
190
-
191
- const jobs = rawJobs.map((jobStr) => {
192
- try {
193
- const parsed = JSON.parse(jobStr)
194
- return { ...parsed, _raw: jobStr }
195
- } catch (_e) {
196
- return { _raw: jobStr, _error: 'Failed to parse JSON' }
197
- }
198
- })
199
-
200
- const persistence = this.manager.getPersistence()
201
- if (jobs.length < stop - start + 1 && persistence && type === 'failed') {
202
- const archived = await persistence.list(queueName, {
203
- limit: stop - start + 1 - jobs.length,
204
- status: type as 'failed',
205
- })
206
- return [...jobs, ...archived.map((a: any) => ({ ...a, _archived: true }))]
207
- }
208
-
209
- return jobs
210
- }
211
- }
212
-
213
- async recordStatusMetrics(
214
- nodes: Record<string, any> = {},
215
- injectedWorkers?: any[]
216
- ): Promise<void> {
217
- const stats = await this.listQueues()
218
- const totals = stats.reduce(
219
- (acc, q) => {
220
- acc.waiting += q.waiting
221
- acc.delayed += q.delayed
222
- acc.failed += q.failed
223
- return acc
224
- },
225
- { waiting: 0, delayed: 0, failed: 0 }
226
- )
227
-
228
- const now = Math.floor(Date.now() / 60000)
229
- const pipe = this.redis.pipeline()
230
-
231
- pipe.set(`flux_console:metrics:waiting:${now}`, totals.waiting, 'EX', 3600)
232
- pipe.set(`flux_console:metrics:delayed:${now}`, totals.delayed, 'EX', 3600)
233
- pipe.set(`flux_console:metrics:failed:${now}`, totals.failed, 'EX', 3600)
234
-
235
- const workers = injectedWorkers || (await this.listWorkers())
236
- pipe.set(`flux_console:metrics:workers:${now}`, workers.length, 'EX', 3600)
237
-
238
- await pipe.exec()
239
-
240
- this.logEmitter.emit('stats', {
241
- queues: stats,
242
- throughput: await this.getThroughputData(),
243
- workers,
244
- })
245
-
246
- this.alerts
247
- .check({
248
- queues: stats,
249
- nodes: nodes as any,
250
- workers: workers as any,
251
- totals,
252
- })
253
- .catch((err) => console.error('[AlertService] Rule Evaluation Error:', err))
254
- }
255
-
256
- onStats(callback: (stats: GlobalStats) => void): () => void {
257
- this.logEmitter.on('stats', callback)
258
- return () => {
259
- this.logEmitter.off('stats', callback)
260
- }
261
- }
262
-
263
- async getMetricHistory(metric: string, limit = 15): Promise<number[]> {
264
- const now = Math.floor(Date.now() / 60000)
265
- const keys = []
266
- for (let i = limit - 1; i >= 0; i--) {
267
- keys.push(`flux_console:metrics:${metric}:${now - i}`)
268
- }
269
-
270
- const values = await this.redis.mget(...keys)
271
- return values.map((v) => parseInt(v || '0', 10))
272
- }
273
-
274
- async getThroughputData(): Promise<{ timestamp: string; count: number }[]> {
275
- const now = Math.floor(Date.now() / 60000)
276
- const results = []
277
-
278
- for (let i = 14; i >= 0; i--) {
279
- const t = now - i
280
- const count = await this.redis.get(`flux_console:throughput:${t}`)
281
- const date = new Date(t * 60000)
282
- results.push({
283
- timestamp: `${date.getHours().toString().padStart(2, '0')}:${date.getMinutes().toString().padStart(2, '0')}`,
284
- count: parseInt(count || '0', 10),
285
- })
286
- }
287
-
288
- return results
289
- }
290
-
291
- async listWorkers(): Promise<WorkerReport[]> {
292
- return this.metricsCollector.listWorkers()
293
- }
294
-
295
- async deleteJob(
296
- queueName: string,
297
- type: 'waiting' | 'delayed' | 'failed',
298
- jobRaw: string
299
- ): Promise<boolean> {
300
- const key =
301
- type === 'delayed'
302
- ? `${this.prefix}${queueName}:delayed`
303
- : type === 'failed'
304
- ? `${this.prefix}${queueName}:failed`
305
- : `${this.prefix}${queueName}`
306
- const result =
307
- type === 'delayed'
308
- ? await this.redis.zrem(key, jobRaw)
309
- : await this.redis.lrem(key, 0, jobRaw)
310
- return result > 0
311
- }
312
-
313
- async retryJob(queueName: string, jobRaw: string): Promise<boolean> {
314
- const key = `${this.prefix}${queueName}`
315
- const delayKey = `${key}:delayed`
316
-
317
- const script = `
318
- local delayKey = KEYS[1]
319
- local queueKey = KEYS[2]
320
- local jobRaw = ARGV[1]
321
-
322
- local removed = redis.call('ZREM', delayKey, jobRaw)
323
- if removed > 0 then
324
- redis.call('LPUSH', queueKey, jobRaw)
325
- return 1
326
- end
327
- return 0
328
- `
329
- const result = await this.redis.eval(script, 2, delayKey, key, jobRaw)
330
- return result === 1
331
- }
332
-
333
- async purgeQueue(queueName: string): Promise<void> {
334
- const pipe = this.redis.pipeline()
335
- pipe.del(`${this.prefix}${queueName}`)
336
- pipe.del(`${this.prefix}${queueName}:delayed`)
337
- pipe.del(`${this.prefix}${queueName}:failed`)
338
- pipe.del(`${this.prefix}${queueName}:active`)
339
- await pipe.exec()
340
- }
341
-
342
- async retryAllFailedJobs(queueName: string): Promise<number> {
343
- return await this.manager.retryFailed(queueName, 10000)
344
- }
345
-
346
- async clearFailedJobs(queueName: string): Promise<void> {
347
- await this.manager.clearFailed(queueName)
348
- }
349
-
350
- async getJobCount(queueName: string, type: 'waiting' | 'delayed' | 'failed'): Promise<number> {
351
- const key =
352
- type === 'delayed'
353
- ? `${this.prefix}${queueName}:delayed`
354
- : type === 'failed'
355
- ? `${this.prefix}${queueName}:failed`
356
- : `${this.prefix}${queueName}`
357
-
358
- return type === 'delayed' ? await this.redis.zcard(key) : await this.redis.llen(key)
359
- }
360
-
361
- async deleteAllJobs(queueName: string, type: 'waiting' | 'delayed' | 'failed'): Promise<number> {
362
- const key =
363
- type === 'delayed'
364
- ? `${this.prefix}${queueName}:delayed`
365
- : type === 'failed'
366
- ? `${this.prefix}${queueName}:failed`
367
- : `${this.prefix}${queueName}`
368
-
369
- const count = await this.getJobCount(queueName, type)
370
- await this.redis.del(key)
371
- return count
372
- }
373
-
374
- async retryAllJobs(queueName: string, type: 'delayed' | 'failed'): Promise<number> {
375
- if (type === 'delayed') {
376
- return await this.retryDelayedJob(queueName)
377
- } else {
378
- return await this.retryAllFailedJobs(queueName)
379
- }
380
- }
381
-
382
- async deleteJobs(
383
- queueName: string,
384
- type: 'waiting' | 'delayed' | 'failed',
385
- jobRaws: string[]
386
- ): Promise<number> {
387
- const key =
388
- type === 'delayed'
389
- ? `${this.prefix}${queueName}:delayed`
390
- : type === 'failed'
391
- ? `${this.prefix}${queueName}:failed`
392
- : `${this.prefix}${queueName}`
393
-
394
- const pipe = this.redis.pipeline()
395
- for (const raw of jobRaws) {
396
- if (type === 'delayed') {
397
- pipe.zrem(key, raw)
398
- } else {
399
- pipe.lrem(key, 1, raw)
400
- }
401
- }
402
- const results = await pipe.exec()
403
- return results?.reduce((acc, [_, res]) => acc + ((res as number) || 0), 0) || 0
404
- }
405
-
406
- async retryJobs(
407
- queueName: string,
408
- type: 'delayed' | 'failed',
409
- jobRaws: string[]
410
- ): Promise<number> {
411
- const key = `${this.prefix}${queueName}`
412
- const sourceKey = type === 'delayed' ? `${key}:delayed` : `${key}:failed`
413
-
414
- const pipe = this.redis.pipeline()
415
- for (const raw of jobRaws) {
416
- if (type === 'delayed') {
417
- pipe.zrem(sourceKey, raw)
418
- pipe.lpush(key, raw)
419
- } else {
420
- pipe.lrem(sourceKey, 1, raw)
421
- pipe.lpush(key, raw)
422
- }
423
- }
424
- const results = await pipe.exec()
425
- let count = 0
426
- if (results) {
427
- for (let i = 0; i < results.length; i += 2) {
428
- const result = results[i]
429
- if (result && !result[0] && (result[1] as number) > 0) {
430
- count++
431
- }
432
- }
433
- }
434
- return count
435
- }
436
-
437
- async publishLog(log: { level: string; message: string; workerId: string; queue?: string }) {
438
- const payload = {
439
- ...log,
440
- timestamp: new Date().toISOString(),
441
- }
442
- await this.redis.publish('flux_console:logs', JSON.stringify(payload))
443
-
444
- const pipe = this.redis.pipeline()
445
- pipe.lpush('flux_console:logs:history', JSON.stringify(payload))
446
- pipe.ltrim('flux_console:logs:history', 0, 99)
447
-
448
- const now = Math.floor(Date.now() / 60000)
449
- pipe.incr(`flux_console:throughput:${now}`)
450
- pipe.expire(`flux_console:throughput:${now}`, 3600)
451
-
452
- await pipe.exec()
453
-
454
- const persistence = this.manager.getPersistence()
455
- if (persistence) {
456
- persistence
457
- .archiveLog({
458
- ...log,
459
- timestamp: new Date(),
460
- })
461
- .catch((err: any) => console.error('[QueueService] Log Archive Error:', err))
462
- }
463
- }
464
-
465
- async getLogHistory(): Promise<any[]> {
466
- const logs = await this.redis.lrange('flux_console:logs:history', 0, -1)
467
- return logs.map((l) => JSON.parse(l)).reverse()
468
- }
469
-
470
- async searchJobs(
471
- query: string,
472
- options: { limit?: number; type?: 'all' | 'waiting' | 'delayed' | 'failed' } = {}
473
- ): Promise<any[]> {
474
- const { limit = 20, type = 'all' } = options
475
- const results: any[] = []
476
- const queryLower = query.toLowerCase()
477
-
478
- const queues = await this.listQueues()
479
-
480
- for (const queue of queues) {
481
- if (results.length >= limit) {
482
- break
483
- }
484
-
485
- const types = type === 'all' ? ['waiting', 'delayed', 'failed'] : [type]
486
-
487
- for (const jobType of types) {
488
- if (results.length >= limit) {
489
- break
490
- }
491
-
492
- const jobs = await this.getJobs(queue.name, jobType as any, 0, 99)
493
-
494
- for (const job of jobs) {
495
- if (results.length >= limit) {
496
- break
497
- }
498
-
499
- const idMatch = job.id && String(job.id).toLowerCase().includes(queryLower)
500
- const nameMatch = job.name && String(job.name).toLowerCase().includes(queryLower)
501
-
502
- let dataMatch = false
503
- try {
504
- const dataStr = JSON.stringify(job.data || job).toLowerCase()
505
- dataMatch = dataStr.includes(queryLower)
506
- } catch (_e) {}
507
-
508
- if (idMatch || nameMatch || dataMatch) {
509
- results.push({
510
- ...job,
511
- _queue: queue.name,
512
- _type: jobType,
513
- _matchType: idMatch ? 'id' : nameMatch ? 'name' : 'data',
514
- })
515
- }
516
- }
517
- }
518
- }
519
-
520
- return results
521
- }
522
-
523
- async getArchiveJobs(
524
- queue: string,
525
- page = 1,
526
- limit = 50,
527
- status?: 'completed' | 'failed',
528
- filter: { jobId?: string; startTime?: Date; endTime?: Date } = {}
529
- ): Promise<{ jobs: any[]; total: number }> {
530
- const persistence = this.manager.getPersistence()
531
- if (!persistence) {
532
- return { jobs: [], total: 0 }
533
- }
534
-
535
- const offset = (page - 1) * limit
536
- const [jobs, total] = await Promise.all([
537
- persistence.list(queue, { limit, offset, status, ...filter }),
538
- persistence.count(queue, { status, ...filter }),
539
- ])
540
-
541
- return {
542
- jobs: jobs.map((j: any) => ({ ...j, _archived: true })),
543
- total,
544
- }
545
- }
546
-
547
- async searchArchive(
548
- query: string,
549
- options: { limit?: number; page?: number; queue?: string } = {}
550
- ): Promise<{ jobs: any[]; total: number }> {
551
- const persistence = this.manager.getPersistence() as any
552
- if (!persistence || typeof persistence.search !== 'function') {
553
- return { jobs: [], total: 0 }
554
- }
555
-
556
- const { limit = 50, page = 1, queue } = options
557
- const offset = (page - 1) * limit
558
-
559
- const jobs = await persistence.search(query, { limit, offset, queue })
560
- return {
561
- jobs: jobs.map((j: any) => ({ ...j, _archived: true })),
562
- total: jobs.length === limit ? limit * page + 1 : (page - 1) * limit + jobs.length,
563
- }
564
- }
565
-
566
- async getArchivedLogs(
567
- options: {
568
- page?: number
569
- limit?: number
570
- level?: string
571
- workerId?: string
572
- queue?: string
573
- search?: string
574
- startTime?: Date
575
- endTime?: Date
576
- } = {}
577
- ): Promise<{ logs: any[]; total: number }> {
578
- const persistence = this.manager.getPersistence()
579
- if (!persistence) {
580
- return { logs: [], total: 0 }
581
- }
582
-
583
- const { page = 1, limit = 50, ...filters } = options
584
- const offset = (page - 1) * limit
585
-
586
- const [logs, total] = await Promise.all([
587
- persistence.listLogs({ limit, offset, ...filters }),
588
- persistence.countLogs(filters),
589
- ])
590
-
591
- return { logs, total }
592
- }
593
-
594
- async cleanupArchive(days: number): Promise<number> {
595
- const persistence = this.manager.getPersistence()
596
- if (!persistence) {
597
- return 0
598
- }
599
- return await persistence.cleanup(days)
600
- }
601
-
602
- async listSchedules(): Promise<any[]> {
603
- const scheduler = this.manager.getScheduler()
604
- return await scheduler.list()
605
- }
606
-
607
- async registerSchedule(config: {
608
- id: string
609
- cron: string
610
- queue: string
611
- job: any
612
- }): Promise<void> {
613
- const scheduler = this.manager.getScheduler()
614
- await scheduler.register(config)
615
- }
616
-
617
- async removeSchedule(id: string): Promise<void> {
618
- const scheduler = this.manager.getScheduler()
619
- await scheduler.remove(id)
620
- }
621
-
622
- async runScheduleNow(id: string): Promise<void> {
623
- const scheduler = this.manager.getScheduler()
624
- await scheduler.runNow(id)
625
- }
626
-
627
- async tickScheduler(): Promise<void> {
628
- const scheduler = this.manager.getScheduler()
629
- await scheduler.tick()
630
- }
631
- }