Poller Hub
A suite of job-monitoring tools I built for my own job search: five targeted watchers, phone alerts, and a dashboard for managing the original three monitors.
More building.
The starting point
I was checking different places for different signals: an application button becoming available, a new early-career role, or a posting in a specific city. Each source had its own format and filtering rules. I built the pollers to do those repeated checks and tell me when something worth opening appeared.
What I built
The suite grew into five watchers, each with a specific job:
- Google Careers: uses Playwright to detect when an Apply button appears on a selected posting, with fallback selectors. It stops after a match and can open the application link.
- Notion Early Career: looks for new software-engineering roles matching configurable keywords, then keeps watching after each alert.
- SimplifyJobs: reads the new-grad repository README and detects newly added, open Software Engineering rows.
- SAP New Grad: scans Canadian, US, and engineering-academy listings, follows pagination, and checks job descriptions for explicit entry-level eligibility and a working Apply link.
- SAP Montreal / Vancouver: monitors Canadian postings across the newer recruiting feed and legacy careers site. It includes all job levels, normalizes accented city names, and merges matching title-and-city results across sources within a scan.
I also built a Vite dashboard and a separate Node.js worker for the Google, Notion, and SimplifyJobs monitors. The worker reads enabled monitors and intervals, saves hits and seen items in Supabase, sends ntfy phone alerts, and reports a heartbeat. The two SAP watchers remain standalone, with their own settings and saved state.
Under the hood
The continuous listing watchers establish a silent baseline so the first run does not flood my phone with existing jobs. Saved history lets them distinguish new listings from ones they already know about.
The SAP watchers add a persistent notification queue, non-overlapping scans, error backoff, and a lock against two processes writing the same state. Failed deliveries stay queued across restarts. Source failures remain visible instead of being treated as an empty job list; in the two-source city watcher, the other source can still finish its scan.
These are locally running workers, so the computer needs to stay awake and connected. Notifications are not exactly-once: a crash after delivery but before saving state can repeat an alert. Keeping that limitation explicit matters more than claiming perfect delivery.
What stayed with me
The useful part of this project became the behavior between checks: remembering what I had seen, filtering out irrelevant jobs, recovering from failed requests, and making a stopped worker visible. A single Apply-button detector and a continuous listing monitor need different stopping rules. Keeping those rules explicit let the suite grow without forcing every source into the same behavior.