Changes
- Graceful shutdown on
SIGTERM/SIGINT. PreviouslySIGTERM(sent bysystemctl stop,docker stop, and Kubernetes pod termination) killed the process mid-batch, tearing output writes and silently dropping Kafka producer buffers. parsedmarc now sets a shutdown flag that is polled at safe boundaries: the one-shot CLI checks it between batches, and the watcher passes it asconfig_reloadingso the mailbox backend — including the IMAP IDLE loop — returns once the current batch is processed. Either way the current batch and its output writes finish before the process exits. Ctrl-C is a double-tap: the first press is graceful, the second short-circuits toos._exit(130). This requires theconfig_reloading-aware IMAP IDLE loop from the pinnedmailsuitefork; with a stockmailsuitethe IDLE watcher cannot be interrupted cleanly. (PR #794)- Output clients are now closed on every exit path via
atexitplus a trailing close at the end of_main(), fixing a long-standing leak where one-shot CLI runs and graceful shutdowns never flushed Kafka / closed Elasticsearch / S3 / etc. clients. - Example systemd unit in
docs/source/usage.mdnow setsKillSignal=SIGTERMandTimeoutStopSec=60so systemd waits long enough for the watcher to drain (keep it abovemailbox_check_timeout).
- Output clients are now closed on every exit path via
- Switch the Kafka client dependency from
kafka-python-ngback tokafka-python>=2.3.2(#795).kafka-python-ngwas a fork created whilekafka-pythonwas unmaintained; upstreamkafka-pythonis active again, and the now-archived fork is vulnerable to CVE-2026-10142 and CVE-2026-10143, both fixed inkafka-python2.3.2. Both packages install the samekafkamodule, so if you are upgrading an existing environment in place withpip, runpip uninstall kafka-python-ngbefore upgrading parsedmarc so the two distributions don't conflict with each other's files.- parsedmarc is compatible with both
kafka-python2.3.2+ and 3.x:kafka-python3.0 removed theNoBrokersAvailableexception (a failed bootstrap now raisesKafkaTimeoutError), and parsedmarc handles whichever the installed version provides.
- parsedmarc is compatible with both
- The whole codebase (library and tests) now passes
pyrightwith zero errors and warnings, and CI enforces this (plusruff format --check) on every push and pull request. Pyright is configured inpyproject.toml([tool.pyright]) and pinned in the[build]extra. The fixes are annotation-level only (Optionalparameters, TypedDict-aware signatures on the syslog/GELF save methods,TYPE_CHECKING-aware optional imports forpsycopgand thekafka-python2.x/3.x bootstrap-error fallback) — runtime behavior is unchanged apart from theSyslogClientfix below. Builds on the class-body alias declarations from #797.
Bug fixes
SyslogClient: constructing a TCP/TLS client withretry_attempts< 1 now raisesValueErrorinstead of silently skipping the connection loop and registering a broken (None) log handler.