ADR-0032: Plugin Pool WaitGroup Drain + Context Cancellation
Status: Accepted
Date: 2026-06-12
Author: @johalputt
Context
The plugin goroutine pool was not draining cleanly on shutdown. Workers could be mid-execution when close(pluginQueue) was called, causing panics or lost work. Context cancellation was not propagated to plugin goroutines.
Decision
- Add a
sync.WaitGroup(workerPluginWg) that each plugin goroutine increments on start and decrements on exit. - Propagate the shutdown context to all plugin goroutines so they exit cleanly on cancellation.
- On shutdown:
close(pluginQueue)→workerPluginWg.Wait()to ensure all in-flight plugin jobs complete. - Each goroutine wraps its execution in
recover()to isolate panics — a panicking plugin cannot crash the process. pluginFailuresuses atomic operations.pluginDisabledusessync.Map.
Rationale
Without WaitGroup drain, a shutdown race where a plugin goroutine is mid-write to SQLite corrupts the write job state and leaves articles in processing limbo. The stuck-job reaper recovers these on next start, but it's operationally cleaner to drain first.
Consequences
- Positive: Clean shutdown; no stuck jobs from plugin mid-execution.
- Positive: Panic isolation — a bad plugin does not crash VayuPress.
- Negative: Shutdown may be delayed by up to one plugin job's processing time (~1s typical).