Repository navigation
Fix gateway jobs: deliver incoming updates, build Telethon events, resolve @chat refs, start jobs at boot - #43
Merged
Merged
Conversation
…ng updates reach the bus SessionManager.ensure() called the ready hook straight after AccountSession.start(), which only schedules the supervisor. The client did not exist yet, so _attach_handlers returned early and no incoming update ever reached the bus: jobs, webhooks and watch saw the daemon's own sends only, and every gateway job stopped with matched=0 skipped=0. The session now calls an on_client hook from the supervisor right after it builds the client, before the private-API hooks that can raise. The client is kept across reconnects, so the handler is attached once.
MessageBox declares __slots__, so assigning apply_difference on the instance raised AttributeError on every account's first connect. The account logged 'degraded', burned one reconnect, and then ran without the hook, because the retry reuses the client and skips _install_hooks. The box now moves onto a subclass built for that client. It adds no slots, so __class__ assignment is allowed, and other clients keep the plain class. The new tests use Telethon's real MessageBox; the fake client has none, which is why this was never caught.
…s, so jobs can match Two faults hid behind the dispatch bug fixed earlier: - The bus hands a job the raw TL update (UpdateNewChannelMessage), but every filter and action reads a high-level event: event.chat_id, is_private, reply(). The job now builds the event with the builder a Telethon handler would have used, attaches entities and client the way _dispatch_update does, and applies the builder's filter. That also restores NewMessage(incoming=True), so an auto-reply job no longer answers the account's own messages. - filter_chat_id skips '@name' refs on the promise that the gateway resolves them, and nothing did, so 'chat_id: "@channel"' never matched, in v1 either. setup() now resolves them through the job client, and logs a ref it cannot resolve. The fake client gains _mb_entity_cache, _self_id and parse_mode, which Telethon's events read, so the new tests drive real builders and TL updates.
…t failed while offline reload_jobs() ran only on 'tlgr job reload', so every daemon restart left the gateway with no jobs until someone noticed. On the live install that was from 2026-09-30 to 2026-10-03, across seven restarts. run() now starts the jobs in a background task once accounts are connected, so readiness does not wait for a job's account, and shutdown cancels it. Because a job can now start while its account is still offline, a '@chat' ref that fails to resolve is retried from the event path, at most once a minute, instead of leaving the job unable to match for good.
…ing '-' for both JobState inherited omit_defaults, so an enabled job dropped 'enabled' (True is the default) and a stopped one dropped 'running' (False is the default). The table renders a missing field as '-', so an enabled, stopped job looked exactly like a disabled one. Same fix and reasoning as DaemonStatus.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Gateway jobs have never matched a message under the v2 daemon. On the live install every job stopped with
matched=0 skipped=0, and after a restart on 2026-09-30 no jobs ran at all. Four faults stacked up, and each one alone was enough to stop every job.What was wrong
SessionManager.ensure()called the ready hook straight afterAccountSession.start(), which only schedules the supervisor.session.clientwas stillNone, so_attach_handlersreturned early. Jobs, webhooks andwatchsaw the daemon's own sends only. Evidence: the liveNeoaccount'sevents.stateis{"seq": 1}.UpdateNewChannelMessage), but every filter and action reads a Telethon high-level event (event.chat_id,is_private,reply()).chat_id: "@name"never matched.filter_chat_idskips string refs, expecting the gateway to resolve them, and nothing did, in v1 either.reload_jobs()ran only ontlgr job reload.Also fixed along the way:
apply_difference is read-onlyon every account's first connect.MessageBoxhas__slots__, so the too-long hook failed, cost one reconnect, and was then skipped.job listshowed-forenabledandrunningbecauseJobStateomitted fields at their defaults.Changes
daemon/session.py,daemon/sessions.py,daemon/app.py: the session calls anon_clienthook from the supervisor once it builds the client. That happens once per session, since the client survives reconnects.core/telethon_compat.py: the too-long hook moves the box onto a per-client subclass with no extra slots, instead of assigning to the instance.gateway/engine.py: the bus path builds the event with the same builder a Telethon handler uses and applies its filter, which restoresNewMessage(incoming=True)so auto-replies skip the account's own messages.setup()resolves@chatrefs, and a ref that failed (account offline) is retried at most once a minute.daemon/app.py:run()starts the jobs in a background task after accounts connect, and shutdown cancels it.models/daemon.py:JobStateusesomit_defaults=False, likeDaemonStatus.Tests
New tests use real Telethon TL types and builders. The fake client gains
_mb_entity_cache,_self_idandparse_mode, which Telethon events read. Each new test file fails against the old code.tests/test_daemon_updates.py: an incoming update is numbered on the bus, and the handler is attached exactly once across reconnects.tests/test_telethon_compat.py: the hook installs on a realMessageBox, reports a gap, and does not leak to another client.tests/test_gateway_bus.py: forward, processed copy, account isolation, private auto-reply, no reply to own messages, ref resolution and retry.tests/test_daemon_jobs.py: enabled jobs run after boot, and a brokenjobs.yamldoes not stop the daemon.make lint typecheck test docs parity: all pass, 13324 tests.Not in this PR
WebhookPusher.should_pushevaluates webhook filters against the raw TL update too, the same shape bug as item 2. That is left for a follow-up.Deploying
After merging, the live daemon needs a restart (
tlgr daemon restart) to pick this up. The jobs then start on their own.