mirror of
https://github.com/openclaw/openclaw.git
synced 2026-06-02 11:07:14 +00:00
fix: recover telegram polling after runner stop (#26447) (thanks @theclawdaddy)
This commit is contained in:
@@ -14,6 +14,7 @@ Docs: https://docs.openclaw.ai
|
|||||||
### Fixes
|
### Fixes
|
||||||
|
|
||||||
- Agents/Subagents delivery: refactor subagent completion announce dispatch into an explicit queue/direct/fallback state machine, recover outbound channel-plugin resolution in cold/stale plugin-registry states across announce/message/gateway send paths, finalize cleanup bookkeeping when announce flow rejects, and treat Telegram sends without `message_id` as delivery failures (instead of false-success `"unknown"` IDs). (#26867, #25961, #26803, #25069, #26741) Thanks @SmithLabsLLC and @docaohieu2808.
|
- Agents/Subagents delivery: refactor subagent completion announce dispatch into an explicit queue/direct/fallback state machine, recover outbound channel-plugin resolution in cold/stale plugin-registry states across announce/message/gateway send paths, finalize cleanup bookkeeping when announce flow rejects, and treat Telegram sends without `message_id` as delivery failures (instead of false-success `"unknown"` IDs). (#26867, #25961, #26803, #25069, #26741) Thanks @SmithLabsLLC and @docaohieu2808.
|
||||||
|
- Telegram/Polling: keep the polling monitor alive when the grammY runner stops unexpectedly under an active gateway abort lifecycle, auto-restarting with backoff instead of exiting silently. (#26447) Thanks @theclawdaddy.
|
||||||
- Slack/Session threads: prevent oversized parent-session inheritance from silently bricking new thread sessions, surface embedded context-overflow empty-result failures to users, and add configurable `session.parentForkMaxTokens` (default `100000`, `0` disables). (#26912) Thanks @markshields-tl.
|
- Slack/Session threads: prevent oversized parent-session inheritance from silently bricking new thread sessions, surface embedded context-overflow empty-result failures to users, and add configurable `session.parentForkMaxTokens` (default `100000`, `0` disables). (#26912) Thanks @markshields-tl.
|
||||||
- Security/Signal: enforce DM/group authorization before reaction-only notification enqueue so unauthorized senders can no longer inject Signal reaction system events under `dmPolicy`/`groupPolicy`; reaction notifications now require channel access checks first. This ships in the next npm release (`2026.2.25`). Thanks @tdjackey for reporting.
|
- Security/Signal: enforce DM/group authorization before reaction-only notification enqueue so unauthorized senders can no longer inject Signal reaction system events under `dmPolicy`/`groupPolicy`; reaction notifications now require channel access checks first. This ships in the next npm release (`2026.2.25`). Thanks @tdjackey for reporting.
|
||||||
- Security/Discord + Slack reactions: enforce DM policy/allowlist authorization before reaction-event system enqueue in direct messages; Discord reaction handling now also honors DM/group-DM enablement and guild `groupPolicy` channel gating to keep reaction ingress aligned with normal message preflight. This ships in the next npm release (`2026.2.25`). Thanks @tdjackey for reporting.
|
- Security/Discord + Slack reactions: enforce DM policy/allowlist authorization before reaction-event system enqueue in direct messages; Discord reaction handling now also honors DM/group-DM enablement and guild `groupPolicy` channel gating to keep reaction ingress aligned with normal message preflight. This ships in the next npm release (`2026.2.25`). Thanks @tdjackey for reporting.
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ vi.mock("../../commands/agent.js", () => ({
|
|||||||
|
|
||||||
vi.mock("../../config/config.js", () => ({
|
vi.mock("../../config/config.js", () => ({
|
||||||
loadConfig: () => mocks.loadConfigReturn,
|
loadConfig: () => mocks.loadConfigReturn,
|
||||||
|
STATE_DIR: "/tmp/openclaw-test-state",
|
||||||
}));
|
}));
|
||||||
|
|
||||||
vi.mock("../../agents/agent-scope.js", () => ({
|
vi.mock("../../agents/agent-scope.js", () => ({
|
||||||
|
|||||||
@@ -229,6 +229,30 @@ describe("monitorTelegramProvider (grammY)", () => {
|
|||||||
expect(runSpy).toHaveBeenCalledTimes(2);
|
expect(runSpy).toHaveBeenCalledTimes(2);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("restarts polling when runner stops unexpectedly under active abort signal", async () => {
|
||||||
|
const abort = new AbortController();
|
||||||
|
runSpy
|
||||||
|
.mockImplementationOnce(() => ({
|
||||||
|
task: () => Promise.resolve(),
|
||||||
|
stop: vi.fn(),
|
||||||
|
isRunning: (): boolean => false,
|
||||||
|
}))
|
||||||
|
.mockImplementationOnce(() => ({
|
||||||
|
task: () => {
|
||||||
|
abort.abort();
|
||||||
|
return Promise.resolve();
|
||||||
|
},
|
||||||
|
stop: vi.fn(),
|
||||||
|
isRunning: (): boolean => false,
|
||||||
|
}));
|
||||||
|
|
||||||
|
await monitorTelegramProvider({ token: "tok", abortSignal: abort.signal });
|
||||||
|
|
||||||
|
expect(computeBackoff).toHaveBeenCalled();
|
||||||
|
expect(sleepWithAbort).toHaveBeenCalled();
|
||||||
|
expect(runSpy).toHaveBeenCalledTimes(2);
|
||||||
|
});
|
||||||
|
|
||||||
it("deletes webhook before starting polling", async () => {
|
it("deletes webhook before starting polling", async () => {
|
||||||
const order: string[] = [];
|
const order: string[] = [];
|
||||||
api.deleteWebhook.mockReset();
|
api.deleteWebhook.mockReset();
|
||||||
|
|||||||
@@ -45,10 +45,8 @@ export function createTelegramRunnerOptions(cfg: OpenClawConfig): RunOptions<unk
|
|||||||
},
|
},
|
||||||
// Suppress grammY getUpdates stack traces; we log concise errors ourselves.
|
// Suppress grammY getUpdates stack traces; we log concise errors ourselves.
|
||||||
silent: true,
|
silent: true,
|
||||||
// Retry transient failures before surfacing errors. Use a generous
|
// Retry transient failures for a limited window before surfacing errors.
|
||||||
// window so the runner survives prolonged outages (e.g. scheduled
|
maxRetryTime: 5 * 60 * 1000,
|
||||||
// internet downtime) without the outer loop needing to restart it.
|
|
||||||
maxRetryTime: 60 * 60 * 1000,
|
|
||||||
retryInterval: "exponential",
|
retryInterval: "exponential",
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@@ -279,7 +277,7 @@ export async function monitorTelegramProvider(opts: MonitorTelegramOpts = {}) {
|
|||||||
try {
|
try {
|
||||||
// runner.task() returns a promise that resolves when the runner stops
|
// runner.task() returns a promise that resolves when the runner stops
|
||||||
await runner.task();
|
await runner.task();
|
||||||
if (opts.abortSignal?.aborted) {
|
if ((!opts.abortSignal || opts.abortSignal.aborted) && !forceRestarted) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// The runner stopped on its own. This can happen when grammY's
|
// The runner stopped on its own. This can happen when grammY's
|
||||||
|
|||||||
Reference in New Issue
Block a user