0) Problem Restatement
LinkedIn asked: design a system that detects and resolves stale job postings in a large job marketplace. A listing is stale when it's no longer really open: it was filled, closed on the employer's own site, abandoned by the poster, is a duplicate, or is simply old. Stale jobs waste job seekers' time and hurt trust, but closing a job that's actually open hurts employers.
1) Signals of Staleness
| Signal | What it suggests |
|---|---|
| Source page (employer career site / ATS) returns 404 or "position filled" | Closed elsewhere |
| ATS feed no longer includes the job | Closed |
| Poster hasn't logged in, viewed applicants or replied for weeks | Abandoned |
| Many applications, zero recruiter actions | Abandoned / filled |
| Listing age far beyond typical time-to-fill for that role | Probably filled |
| Near-identical listing posted recently by the same company | Duplicate (the older one is stale) |
| Job seekers' reports ("this job is closed") | Direct evidence |
2) Architecture
Architecture Diagram
flowchart LR
JOBS[("Job listings")] --> SCH["Check scheduler - prioritized"]
SCH --> CR["Source checker - crawl apply URL / ATS API"]
ACT["Recruiter activity + applicant events"] --> FE["Feature builder"]
CR --> FE
REP["Seeker reports"] --> FE
FE --> SC["Staleness scorer - rules + ML"]
SC --> DEC["Decision engine"]
DEC -->|"high confidence"| CLOSE["Auto-close + notify employer"]
DEC -->|"medium"| ASK["Ask employer to confirm + demote in search"]
DEC -->|"low"| KEEP["Keep, recheck later"]
CLOSE --> JOBS
ASK --> JOBS3) Key Parts
- Source checks: for jobs imported from ATS feeds or career pages, re-fetch the source regularly. Prioritize popular listings (many views) and old ones, and back off for recently verified ones. Respect crawl politeness.
- Features: listing age vs typical for the role and location, days since the last recruiter action, applicant count, source status, duplicate similarity (text embeddings + company + title + location), and seeker reports.
- Scoring: start with clear rules (the source says closed → stale), plus an ML model trained on labeled outcomes (employer-confirmed closures, jobs that closed soon after) that outputs a probability.
- Actions by confidence:
- Very high (the source confirms closed) → auto-close and notify the employer (with an easy "reopen").
- Medium → ask the employer to confirm ("Is this job still open?" email or in-app), and demote it in search meanwhile.
- Low → keep, and recheck later.
- Duplicates: keep the newest and merge or redirect the older ones.
4) Measuring Success
- The stale rate in search results (sampled and labeled), the rate of seekers applying to closed jobs, and the report rate.
- False closures: employer reopen rate after auto-close (must stay very low), used to tune thresholds.
- An A/B test on demotion: apply rates and seeker satisfaction.
5) Wrap-Up
Combine signals of staleness (source/ATS status, recruiter inactivity, listing age vs typical fill time, duplicate detection and seeker reports) through a prioritized checking pipeline into a staleness score from rules plus ML. Act by confidence: auto-close with easy reopen when the source confirms, ask employers and demote in search when uncertain, recheck otherwise. Measure stale-rate reduction against false closures.