* Cron maintenance
(gatewayManager: GatewayManager)
| 623 | * Cron maintenance |
| 624 | */ |
| 625 | function registerCronHandlers(gatewayManager: GatewayManager): void { |
| 626 | // Periodic cron job repair: checks for jobs with undefined agentId and repairs them |
| 627 | // This handles cases where cron jobs were created via openclaw CLI without specifying agent |
| 628 | const CRON_AGENT_REPAIR_INTERVAL_MS = 5 * 60 * 1000; // 5 minutes |
| 629 | let _lastRepairErrorLogAt = 0; |
| 630 | const REPAIR_ERROR_LOG_INTERVAL_MS = 60 * 60 * 1000; // 1 hour |
| 631 | setInterval(async () => { |
| 632 | try { |
| 633 | const status = gatewayManager.getStatus(); |
| 634 | if (status.state !== 'running') return; |
| 635 | |
| 636 | const result = await gatewayManager.rpc('cron.list', { includeDisabled: true }); |
| 637 | const jobs = Array.isArray(result) |
| 638 | ? result |
| 639 | : (result as { jobs?: Array<{ id: string; name: string; sessionTarget?: string; payload?: { kind: string }; delivery?: { mode: string; channel?: string; to?: string; accountId?: string }; state?: Record<string, unknown> }> })?.jobs ?? []; |
| 640 | |
| 641 | for (const job of jobs) { |
| 642 | const jobAgentId = (job as unknown as { agentId?: string }).agentId; |
| 643 | if ( |
| 644 | (job.sessionTarget === 'isolated' || !job.sessionTarget) && |
| 645 | job.payload?.kind === 'agentTurn' && |
| 646 | job.delivery?.mode === 'announce' && |
| 647 | job.delivery?.channel && |
| 648 | jobAgentId === undefined |
| 649 | ) { |
| 650 | const channel = job.delivery.channel; |
| 651 | const accountId = job.delivery.accountId; |
| 652 | const toAddress = job.delivery.to; |
| 653 | |
| 654 | let correctAgentId = await resolveAgentIdFromChannel(channel, accountId); |
| 655 | |
| 656 | // If no accountId, try to resolve it from session history |
| 657 | let resolvedAccountId: string | null = null; |
| 658 | if (!correctAgentId && !accountId && toAddress) { |
| 659 | resolvedAccountId = await resolveAccountIdFromSessionHistory(toAddress, channel); |
| 660 | if (resolvedAccountId) { |
| 661 | correctAgentId = await resolveAgentIdFromChannel(channel, resolvedAccountId); |
| 662 | } |
| 663 | } |
| 664 | |
| 665 | if (correctAgentId) { |
| 666 | console.debug(`Periodic repair: job "${job.name}" agentId undefined -> "${correctAgentId}"`); |
| 667 | // When accountId was resolved via to address, include it in the patch |
| 668 | const patch: Record<string, unknown> = { agentId: correctAgentId }; |
| 669 | if (resolvedAccountId && !accountId) { |
| 670 | patch.delivery = { accountId: resolvedAccountId }; |
| 671 | } |
| 672 | await gatewayManager.rpc('cron.update', { id: job.id, patch }); |
| 673 | } |
| 674 | } |
| 675 | } |
| 676 | } catch (error) { |
| 677 | const now = Date.now(); |
| 678 | if (now - _lastRepairErrorLogAt >= REPAIR_ERROR_LOG_INTERVAL_MS) { |
| 679 | _lastRepairErrorLogAt = now; |
| 680 | console.debug('Periodic cron repair error:', error); |
| 681 | } |
| 682 | } |
no test coverage detected