© 2026 Koder.ai. ਸਾਰੇ ਅਧਿਕਾਰ ਰਾਖਵੇਂ ਹਨ।
ਹੋਮ › ਬਲੌਗ › Cron + ਡੇਟਾਬੇਸ ਪੈਟਰਨ: queue ਦੇ ਬਿਨਾਂ scheduled ਬੈਕਗ੍ਰਾਊਂਡ ਜਾਬਸ
ਮੁੱਦਾ: ਵੱਧ ਇੰਨਫ੍ਰਾਸਟ੍ਰੱਕਚਰ ਬਿਨਾਂ scheduled ਕੰਮ\n\nਅਧਿਕਤਰ ਐਪਸ ਨੂੰ ਬਾਦ ਵਿੱਚ ਜਾਂ ਇੱਕ ਨਿਯਤ ਸ਼ੈਡਿਊਲ send_invoice_emails jsonb (status, run_at) (locked_until) queued failed locked_until locked_until locked_until NULL locked_until \u003c= now() jobs job_runs FOR UPDATE SKIP LOCKED RETURNING locked_until WHERE id = $job_id AND locked_by = $worker_id queued running succeeded failed dead failed dead attempts max_attempts attempts attempts \u003c max_attempts failed dead run_at failed run_at last_error error_code error_type failed_at next_run_at last_stack dead invoice_id user_id + day report_name + report_date sales_report:2026-01-14 invoice_charge:812 sent_emails(idempotency_key) payments(idempotency_key) sent_emails delivered_webhooks(event_id) (type, date) file_generated jobs run_at (status, run_at) run_at running done finished_at queued run_at run_at = now() + (attempts^2) * interval '10 seconds' max_attempts status = 'dead' cleanup_nightly send_weekly_report send_weekly_report (user_id, week_start_date) sent_reports (user_id, week_start_date) idempotency_key attempts dead locked_until user_id invoice_id invoice_id run_at locked_until NOW() run_at status attempts locked_until max_attempts last_error invoice_id dead max_attempts run_at = now() status, run_at`).\n\nਜੇ ਤੁਸੀਂ ਇਸ ਤਰ੍ਹਾਂ ਦੀ setup ਤੇਜ਼ੀ ਨਾਲ ਬਣਾਉਣਾ ਚਾਹੁੰਦੇ ਹੋ, ਤਾਂ Koder.ai (koder.ai) ਤੁਹਾਨੂੰ schema ਤੋਂ deployed Go + PostgreSQL ਐਪ ਤੱਕ ਘੱਟ manual ਵ੍ਹਾਇਰਿੰਗ ਨਾਲ ਮਦਦ ਕਰ ਸਕਦਾ ਹੈ, ਤਾਂ ਜੋ ਤੁਸੀਂ locking, retries, ਅਤੇ idempotency ਨੀਤੀਆਂ 'ਤੇ ਧਿਆਨ ਦੇ ਸਕੋ।\n\nਅਗਰ ਤੁਸੀਂ ਬਾਅਦ ਵਿੱਚ ਇਸ setup ਤੋਂ ਬਾਹਰ ਨਿਕਲਦੇ ਹੋ, ਤਾਂ ਤੁਸੀਂ job lifecycle ਨੂੰ ਸਾਫ਼ ਤਰੀਕੇ ਨਾਲ ਸਿੱਖ ਲਿਆ ਹੋਵੇਗਾ, ਅਤੇ ਉਹੀ ਵਿਚਾਰਾਂ ਪੂਰੇ queue ਸਿਸਟਮ ਨੂੰ ਮੈਪ ਕਰਨ ਵਿੱਚ ਮਦਦ ਕਰਨਗੇ। ਸਮੱਗਰੀ
ਮੁੱਦਾ: ਵੱਧ ਇੰਨਫ੍ਰਾਸਟ੍ਰੱਕਚਰ ਬਿਨਾਂ scheduled ਕੰਮ\n\nਅਧਿਕਤਰ ਐਪਸ ਨੂੰ ਬਾਦ ਵਿੱਚ ਜਾਂ ਇੱਕ ਨਿਯਤ ਸ਼ੈਡਿਊਲ `ਤੇ ਕੰਮ ਚਾਹੀਦਾ ਹੁੰਦਾ ਹੈ: follow-up ਈਮੇਲ ਭੇਜਣੇ, ਰਾਤ ਨੂੰ billing ਚੈੱਕ, ਪੁਰਾਣੇ record ਸਾਫ਼ ਕਰਨਾ, ਇੱਕ ਰਿਪੋਰਟ ਦੁਬਾਰਾ ਬਣਾਉਣਾ ਜਾਂ cache ਤਾਜ਼ਾ ਕਰਨਾ।\n\nਸ਼ੁਰੂ ਵਿੱਚ, ਪੂਰਾ queue ਸਿਸਟਮ ਸ਼ਾਮਲ ਕਰਨਾ ਲੁਭਾਵਣਾ ਹੁੰਦਾ ਹੈ ਕਿਉਂਕਿ ਇਹ background jobs ਦਾ “ਸਹੀ” ਤਰੀਕਾ ਲੱਗਦਾ ਹੈ। ਪਰ queue ਹੋਰ moving parts ਜੋੜਦਾ ਹੈ: ਇੱਕ ਹੋਰ ਸਰਵਿਸ ਚਲਾਉਣੀ, ਮੌਨੀਟਰ ਕਰਨਾਂ, ਡਿਪਲੋਏ ਕਰਨਾਂ ਅਤੇ ਡੀਬੱਗ ਕਰਨਾਂ। ਛੋਟੀ ਟੀਮ (ਜਾਂ ਇਕੱਲਾ ਫاؤنਡਰ) ਲਈ ਇਹ ਵਧੇਰਾ ਭਾਰ ਅਕਸਰ ਤੁਹਾਨੂੰ ਧੀਰਾ ਕਰ ਦਿੰਦਾ ਹੈ।\n\nਅਸਲ ਸਵਾਲ ਇਹ ਹੈ: ਤੁਸੀਂ ਵਧੇਰਾ ਇੰਨਫ੍ਰਾਸਟ੍ਰੱਕਚਰ ਬਣਾਏ ਬਿਨਾਂ scheduled ਕੰਮ ਕਿਵੇਂ ਭਰੋਸੇਯੋਗ ਢੰਗ ਨਾਲ ਚਲਾਓਗੇ?\n\nਇੱਕ ਆਮ ਪਹਿਲਾ ਯਤਨ ਸਧਾਰਨ ਹੁੰਦਾ ਹੈ: ਇੱਕ cron ਐਂਟਰੀ ਜੋ ਇੱਕ endpoint ਨੂੰ ਹਿੱਟ ਕਰਦੀ ਹੈ, ਅਤੇ ਉਹ endpoint ਕੰਮ ਕਰਦਾ ਹੈ। ਇਹ ਤਦ ਤੱਕ ਠੀਕ ਰਹਿੰਦਾ ਹੈ ਜਦ ਤੱਕ ਇਹ ਨਹੀ ਰੁਕਦਾ। ਜਦੋਂ ਤੁਹਾਡੇ ਕੋਲ ਇੱਕ ਤੋਂ ਵੱਧ ਸਰਵਰ ਹੁੰਦੇ ਹਨ, ਗਲਤ ਸਮੇਂ ਡਿਪਲੋਏ ਹੁੰਦਾ ਹੈ, ਜਾਂ ਕੋਈ job ਉਮੀਦ ਤੋਂ ਲੰਮਾ ਲੈਂਦੀ ਹੈ, ਤਾਂ ਤੁਸੀਂ ਅਜਿਹੀਆਂ ਹੇਠਾਂ ਦਿੱਤੀਆਂ ਸਮੱਸਿਆਵਾਂ ਵੇਖਦੇ ਹੋ।\n\nScheduled ਕੰਮ ਆਮ ਤੌਰ 'ਤੇ ਕੁਝ ਪੈਟਰਨਾਂ ਵਿੱਚ ਟੁੱਟਦਾ ਹੈ:\n\n- ਦੋਹਰਾ ਚਲਾਉਣਾ: ਦੋ ਸਰਵਰ ਇੱਕੋ ਹੀ ਟਾਸਕ ਚਲਾਉਂਦੇ ਹਨ, ਇਸ ਕਰਕੇ invoices ਦਫ਼ਤਾ ਰਜਿਸਟਰ ਹੋ ਜਾਂਦੇ ਹਨ ਜਾਂ ਈਮੇਲ ਦੋ ਵਾਰੀ ਭੇਜੇ ਜਾਂਦੇ ਹਨ।\n- ਗੁੰਮ ਹੋਏ ਚਲਾਉਣ: cron کال deploy ਦੌਰਾਨ ਫੇਲ ਹੋ ਜਾਂਦੀ ਹੈ ਅਤੇ ਕੋਈ ਨੋਟਿਸ ਨਹੀਂ ਲੈਂਦਾ ਜਦ ਤੱਕ ਵਰਤੋਂਕਾਰ ਸ਼ਿਕਾਇਤ ਨਾ ਕਰ ਦੇਣ।\n- ਖਾਮੋਸ਼ ਨਾਕਾਮੀਆਂ: job ਇੱਕ ਵਾਰੀ error ਦਿੰਦਾ ਹੈ ਤੇ ਫਿਰ ਕਦੇ ਨਹੀਂ ਚਲਦਾ ਕਿਉਂਕਿ ਕੋਈ retry ਯੋਜ਼ਨਾ ਨਹੀਂ।\n- ਅਧੂਰਾ ਕੰਮ: job ਅੱਧੇ ਰਾਹ 'ਤੇ crash ਹੋ ਕੇ ਡਾਟਾ ਨੂੰ ਅਜੀਬ ਹਾਲਤ ਵਿੱਚ ਛੱਡ ਦਿੰਦਾ ਹੈ।\n- ਕੋਈ ਆਡਿਟ ਟਰੇਲ ਨਹੀਂ: ਤੁਸੀਂ ਨਹੀਂ ਦੱਸ ਸਕਦੇ “ਇਹ ਆਖ਼ਰੀ ਵਾਰ ਕਦੋਂ ਚਲਿਆ?” ਜਾਂ “ਕੱਲ੍ਹ ਰਾਤ ਕੀ ਹੋਇਆ?”\n\nਕਰੋਨ + ਡੇਟਾਬੇਸ ਪੈਟਰਨ ਇਕ ਮੱਧਮਾਰਗ ਹੈ। ਤੁਸੀਂ ਹੁਣ ਵੀ cron ਨੂੰ schedule ਤੇ “ਉਠਾਉਣ” ਲਈ ਵਰਤਦੇ ਹੋ, ਪਰ ਤੁਸੀਂ job ਦੀ ਇਰਾਦਾ ਅਤੇ ਅਵਸਥਾ ਨੂੰ ਆਪਣੇ ਡੇਟਾਬੇਸ ਵਿੱਚ ਸਟੋਰ ਕਰਦੇ ਹੋ ਤਾਂ ਕਿ ਸਿਸਟਮ ਕੋਆਰਡੀਨੇਟ, retry, ਅਤੇ ਕੀ ਹੋਇਆ ਉਹ ਰਿਕਾਰਡ ਕਰ ਸਕੇ।\n\nਇਹ ਉਹਨਾਂ ਹਾਲਤਾਂ ਲਈ ਵਧੀਆ ਹੈ ਜਦੋਂ ਤੁਹਾਡੇ ਕੋਲ ਪਹਿਲਾਂ ਹੀ ਇੱਕ ਡੇਟਾਬੇਸ (ਅਕਸਰ PostgreSQL) ਹੈ, ਕਈ job ਕਿਸਮਾਂ ਘੱਟ ਹਨ, ਅਤੇ ਤੁਸੀਂ ਘੱਟ ops ਨਾਲ ਪੈਦਾ ਹੋਣ ਵਾਲੀ ਭਰੋਸੇਯੋਗ ਵਿਵਹਾਰ ਚਾਹੁੰਦੇ ਹੋ। ਇਹ modern stacks (ਉਦਾਹਰਨ ਵਜੋਂ React + Go + PostgreSQL) 'ਤੇ ਤੇਜ਼ੀ ਨਾਲ ਬਣੇ ਐਪਸ ਲਈ ਕੁਦਰਤੀ ਚੋਣ ਹੈ।\n\nਇਹ ਉਹਨਾਂ ਹਾਲਤਾਂ ਲਈ ਠੀਕ ਨਹੀਂ ਜਦੋਂ ਤੁਹਾਨੂੰ ਬਹੁਤ ਉੱਚ throughput, ਲੰਬੇ-ਚਲਣ ਵਾਲੇ jobs ਜੋ ਪ੍ਰਗਤੀ stream ਕਰਨੇ ਹੋਣ, ਕਈ job ਕਿਸਮਾਂ ਵਿੱਚ ਕੜੀ ordering ਚਾਹੀਦੀ ਹੋਵੇ, ਜਾਂ ਭਾਰੀ fan-out (ਹਰ ਮਿੰਟ ਹਜ਼ਾਰਾਂ sub-tasks) ਹੋਵੇ। ਉਹਨਾਂ ਹਾਲਤਾਂ ਵਿੱਚ ਇੱਕ ਅਸਲੀ queue ਅਤੇ ਡੈਡੀਕੇਟਿਡ workers ਆਮ ਤੌਰ 'ਤੇ ਆਪਣਾ ਫਾਇਦਾ ਦਿਖਾਉਂਦੇ ਹਨ।\n\n## ਸਧਾਰਨ ਭਾਸ਼ਾ ਵਿੱਚ ਮੁੱਖ ਵਿਚਾਰ\n\nਕਰੋਨ + ਡੇਟਾਬੇਸ ਪੈਟਰਨ scheduled background work chalaunda ਹੈ ਬਿਨਾਂ ਪੂਰੇ queue ਸਿਸਟਮ ਦੇ। ਤੁਸੀਂ ਹੁਣ ਵੀ cron (ਜਾਂ ਕੋਈ ਵੀ scheduler) ਵਰਤਦੇ ਹੋ, ਪਰ cron ਇਹ ਨਹੀਂ ਫੈਸਲਾ ਕਰਦਾ ਕਿ ਕੀ ਚਲਾਉਣਾ ਹੈ। ਇਹ ਸਿਰਫ਼ worker ਨੂੰ ਬਾਰ-ਬਾਰ ਜਗਾਉਂਦਾ ਹੈ (ਜ਼ਿਆਦਾਤਰ ਇੱਕ ਮਿੰਟ ਵਿੱਚ ਇੱਕ ਵਾਰੀ)। ਡੇਟਾਬੇਸ ਫੈਸਲਾ ਕਰਦਾ ਹੈ ਕਿ ਕਿਹੜਾ ਕੰਮ ਦੇਣ ਯੋਗ ਹੈ ਅਤੇ ਇਹ ਯਕੀਨੀ ਬਣਾਉਂਦਾ ਹੈ ਕਿ ਹਰ job ਨੂੰ ਕੇਵਲ ਇੱਕ worker ਹੀ ਲੈਂਦਾ ਹੈ।\n\nਇਸਨੂੰ ਇੱਕ ਸਾਂਝਾ ਚੈੱਕਲਿਸਟ ਵਾਲੀ whiteboard ਵਾਂਗ ਸੋਚੋ। Cron ਉਹ ਵਿਅਕਤੀ ਹੈ ਜੋ ਹਰ ਮਿੰਟ ਕਮਰੇ ਵਿੱਚ ਆਉਂਦਾ ਹੈ ਅਤੇ ਕਹਿੰਦਾ ਹੈ, “ਕਿਸੇ ਨੂੰ ਹੁਣ ਕੁਝ ਕਰਨ ਦੀ ਲੋੜ ਹੈ?” ਡੇਟਾਬੇਸ ਉਹ whiteboard ਹੈ ਜੋ ਦਿਖਾਉਂਦਾ ਹੈ ਕਿ ਕੀ ਦੇਣਾ ਹੈ, ਕੀ ਪਹਿਲਾਂ ਹੀ ਲਿਆ ਗਿਆ ਹੈ, ਅਤੇ ਕੀ ਹੋ ਚੁੱਕਾ ਹੈ।\n\nਹਿੱਸੇ ਸਿੱਧੇ ਹਨ:\n\n- ਇੱਕ ਸਿੰਗਲ scheduler trigger ਬਾਰ-ਬਾਰ ਚਲਦਾ ਹੈ।\n- ਇੱਕ jobs ਟੇਬਲ “ਕੀ” ਅਤੇ “ਕਦੋਂ” (due time) ਰੱਖਦੀ ਹੈ, ਨਾਲ ਹੀ status ਅਤੇ attempt count।\n- ਇੱਕ ਜਾਂ ਉਸ ਤੋਂ ਵੱਧ workers ਟੇਬਲ ਨੂੰ poll ਕਰਦੇ ਹਨ, ਇੱਕ job claim ਕਰਦੇ ਹਨ, ਅਤੇ ਕੰਮ ਕਰਦੇ ਹਨ।\n- claim ਕਰਨਾ ਡੇਟਾਬੇਸ ਲਾਕ ਦੀ ਵਰਤੋਂ ਨਾਲ ਹੁੰਦਾ ਹੈ ਤਾਂ ਕਿ ਦੋ workers ਇੱਕੋ row ਨਾ ਲੈ ਲੈਣ।\n- ਡੇਟਾਬੇਸ ਇਹ ਸਤਰੰਸ਼ ਹੈ ਕਿ ਕੀ ਚਲਿਆ, ਕੀ ਫੇਲ ਹੋਇਆ, ਅਤੇ ਕੀ retry ਕਰਨਾ ਚਾਹੀਦਾ ਹੈ।\n\nਉਦਾਹਰਨ: ਤੁਸੀਂ ਹਰ ਸਵੇਰੇ invoice reminders ਭੇਜਣਾ ਚਾਹੁੰਦੇ ਹੋ, ਹਰ 10 ਮਿੰਟ ਬਾਅਦ cache ਤਾਜ਼ਾ ਕਰਨਾ, ਅਤੇ ਰਾਤ ਨੂੰ ਪੁਰਾਣੀਆਂ sessions ਸਾਫ਼ ਕਰਨਾ। ਤਿੰਨ ਵੱਖ-ਵੱਖ cron ਕਮਾਂਡਾਂ ਦੀ ਥਾਂ (ਜੋ ਹਰ ਇੱਕ ਨਾਲ अपना overlap ਅਤੇ ਫੇਲਯੋਗ ਮੋਡ ਰੱਖਦੀਆਂ ਹਨ), ਤੁਸੀਂ job entries ਇੱਕ ਹੀ ਥਾਂ ਸਟੋਰ ਕਰ ਲੈਂਦੇ ਹੋ। Cron ਇੱਕੋ worker ਪ੍ਰਕਿਰਿਆ ਸ਼ੁਰੂ ਕਰਦਾ ਹੈ। Worker Postgres ਨੂੰ ਪੁੱਛਦਾ ਹੈ, “ਹੁਣ ਕੀ ਦੇਣਾ ਚਾਹੀਦਾ ਹੈ?” ਅਤੇ Postgres worker ਨੂੰ ਸੁਰੱਖਿਅਤ ਤਰੀਕੇ ਨਾਲ ਇੱਕ ਵਾਰੀ ਵਿੱਚ ਇੱਕ job claim ਕਰਨ ਦਿੰਦਾ ਹੈ।\n\nਇਹ تدريجي طور ਤੇ ਸਕੇਲ ਹੁੰਦਾ ਹੈ। ਤੁਸੀਂ ਇੱਕ ਸਰਵਰ ਤੇ ਇੱਕ worker ਨਾਲ ਸ਼ੁਰੂ ਕਰ ਸਕਦੇ ਹੋ। ਬਾਅਦ ਵਿੱਚ, ਤੁਸੀਂ ਕਈ ਸਰਵਰਾਂ 'ਤੇ ਪੰਜ workers ਚਲਾ ਸਕਦੇ ਹੋ। Contract ਇੱਕੋ ਰਿਹਾ: ਟੇਬਲ ਹੀ contract ਹੈ।\n\nਮਨੋਦਸ਼ਾ ਸਧਾਰਨ ਹੈ: cron ਸਿਰਫ਼ ਜਾਗਦਾ ਹੈ। ਡੇਟਾਬੇਸ ਟ੍ਰੈਫਿਕ ਕੋਪ ਹੈ ਜੋ ਫੈਸਲਾ ਕਰਦਾ ਹੈ ਕਿ ਕੀ ਚਲ ਸਕਦਾ ਹੈ, ਕੀ ਹੋਇਆ ਉਸਦਾ ਰਿਕਾਰਡ ਰੱਖਦਾ ਹੈ, ਅਤੇ ਜਦੋਂ ਕੁਝ ਗਲਤ ਹੋਵੇ ਤਾਂ ਸਪਸ਼ਟ ਇਤਿਹਾਸ ਦਿੰਦਾ ਹੈ।\n\n## jobs ਟੇਬਲ ਡਿਜ਼ਾਈਨ ਕਰਨਾ (ਇੱਕ عملي schema)\n\nਇਹ ਪੈਟਰਨ ਸਭ ਤੋਂ ਵਧੀਆ ਤਦੋਂ ਕੰਮ ਕਰਦਾ ਹੈ ਜਦੋਂ ਤੁਹਾਡਾ ਡੇਟਾਬੇਸ ਇਹ ਨਿਰਧਾਰਕ ਸਰੋਤ ਬਣ ਜਾਂਦਾ ਹੈ ਕਿ ਕੀ ਚਲਣਾ ਚਾਹੀਦਾ ਹੈ, ਕਦੋਂ ਚਲਣਾ ਚਾਹੀਦਾ ਹੈ, ਅਤੇ ਆਖ਼ਰੀ ਵਾਰ ਕੀ ਹੋਇਆ। schema ੲੁੱਚੇ ਨਹੀਂ ਹੁੰਦੀ, ਪਰ ਛੋਟੀ-ਛੋਟੀ ਚੀਜ਼ਾਂ (lock ਫੀਲਡ ਅਤੇ ਸਹੀ ਇੰਡੈਕਸ) ਜ਼ਰੂਰੀ ਹਨ ਜਦੋਂ load ਵਧਦਾ ਹੈ।\n\n### ਇੱਕ ਟੇਬਲ ਜਾਂ ਦੋ?\n\nਦੋ ਆਮ ਪਹੁੰਚਾਂ:\n\n- **ਇਕ combined ਟੇਬਲ** ਜਦੋਂ ਤੁਸੀਂ ਹਰ job ਦੀ ਆਖ਼ਰੀ ਸਥਿਤੀ 'ਤੇ ਹੀ ਧਿਆਨ ਦਿੰਦੇ ਹੋ (ਸੰਪੂਰਨ, ਘੱਟ joins)।\n- **ਦੋ ਟੇਬਲ** ਜਦੋਂ ਤੁਸੀਂ “ਇਹ job ਕੀ ਹੈ” ਅਤੇ “ਇਸ ਵਾਰੀ ਇੱਕ-ਇੱਕ ਚਲਣ / ਕੋਸ਼ਿਸ਼” ਨੂੰ ਵੱਖਰਾ ਰੱਖਣਾ ਚਾਹੁੰਦੇ ਹੋ (ਵਧੀਆ ਇਤਿਹਾਸ, ਡੀਬੱਗ ਕਰਨ ਵਿੱਚ ਆਸਾਨ)।\n\nਜੇ ਤੁਸੀਂ ਅਕਸਰ ਫੇਲਿਆਵਾਂ ਡੀਬੱਗ ਕਰਨਾ ਚਾਹੁੰਦੇ ਹੋ ਤਾਂ ਇਤਿਹਾਸ ਰੱਖੋ। ਜੇ ਤੁਸੀਂ ਸਭ ਤੋਂ ਛੋਟੀ ਸੰਰਚਨਾ ਚਾਹੁੰਦੇ ਹੋ ਤਾਂ ਇੱਕ ਟੇਬਲ ਨਾਲ ਸ਼ੁਰੂ ਕਰੋ ਅਤੇ ਬਾਅਦ ਵਿੱਚ ਇਤਿਹਾਸ ਜੋੜੋ।\n\n### ਇੱਕ عملي schema (ਦੋ-ਟੇਬਲ ਵਰਜ਼ਨ)\n\nਹੇਠਾਂ PostgreSQL-ਮੈਤਾਬੋਲਿਕ ਲੇਆਊਟ ਹੈ। ਜੇ ਤੁਸੀਂ Go ਨਾਲ PostgreSQL ਬਣਾ ਰਹੇ ਹੋ, ਤਾਂ ਇਹ ਕਾਲਮ structs ਨਾਲ ਅਸਾਨੀ ਨਾਲ ਮੈਪ ਹੋ ਜਾਂਦੇ ਹਨ।\n\n```sql\n-- What should exist (the definition)\ncreate table job_definitions (\n id bigserial primary key,\n job_type text not null,\n payload jsonb not null default '{}'::jsonb,\n schedule text, -- optional: cron-like text if you store it\n max_attempts int not null default 5,\n created_at timestamptz not null default now(),\n updated_at timestamptz not null default now()\n);\n\n-- What should run (each run / attempt group)\ncreate table job_runs (\n id bigserial primary key,\n definition_id bigint references job_definitions(id),\n job_type text not null,\n payload jsonb not null default '{}'::jsonb,\n run_at timestamptz not null,\n status text not null, -- queued | running | succeeded | failed | dead\n attempts int not null default 0,\n max_attempts int not null default 5,\n\n locked_by text,\n locked_until timestamptz,\n\n last_error text,\n created_at timestamptz not null default now(),\n updated_at timestamptz not null default now()\n);\n```\n\nਕੁਝ ਵਿਸ਼ੇਸ਼ ਤੱਥ ਜੋ ਬਾਅਦ ਵਿੱਚ ਦਰਦ ਬਚਾਉਂਦੇ ਹਨ:\n\n- **job_type** ਨੂੰ ਇੱਕ ਛੋਟਾ ਸਤਰ ਰੱਖੋ ਜਿਸ 'ਤੇ ਤੁਸੀਂ ਰਾਊਟ ਕਰ ਸਕੋ (ਜਿਵੇਂ `send_invoice_emails`).\n- **payload** ਨੂੰ `jsonb` ਵਜੋਂ ਸਟੋਰ ਕਰੋ ਤਾਂ ਜੋ ਤੁਸੀਂ ਬਿਨਾਂ ਮਾਈਗ੍ਰੇਸ਼ਨ ਦੇ ਇਸਨੂੰ ਬਦਲ ਸਕੋ।\n- **run_at** ਤੁਹਾਡਾ "ਅਗਲੀ ਨਿਰਧਾਰਤ ਵਾਰੀ" ਹੈ। Cron (ਜਾਂ scheduler ਸਕ੍ਰਿਪਟ) ਇਹ ਸੈੱਟ ਕਰਦਾ ਹੈ, workers ਇਸਨੂੰ ਖਪਤ ਕਰਦੇ ਹਨ।\n- **locked_by** ਅਤੇ **locked_until** workers ਨੂੰ jobs claim ਕਰਨ ਦਿੰਦੀਆਂ ਹਨ ਬਿਨਾਂ ਇਕ-ਦੂਜੇ 'ਤੇ ਚੱਲਣ ਦੇ।\n- **last_error** ਛੋਟੀ ਅਤੇ ਮਨੁੱਖੀ-ਪੜ੍ਹਨਯੋਗ ਹੋਣੀ ਚਾਹੀਦੀ ਹੈ। ਜੇ ਤੁਹਾਨੂੰ stack traces ਚਾਹੀਦੇ ਹਨ ਤਾਂ ਉਹ ਹੋਰ ਥਾਂ ਰੱਖੋ।\n\n### ਉਹ ਇੰਡੈਕਸ ਜੋ ਤੁਸੀਂ ਚਾਹੁੰਦੇ ਹੋ\n\nਬਿਨਾਂ ਇੰਡੈਕਸਾਂ ਦੇ, workers ਜ਼ਿਆਦਾ scan ਕਰਨਗੇ। ਸ਼ੁਰੂਆਤ ਲਈ:\n\n- ਇੱਕ ਇੰਡੈਕਸ ਜੋ due work ਤੇਜ਼ੀ ਨਾਲ ਲੱਭੇ: `(status, run_at)`\n- ਇੱਕ ਇੰਡੈਕਸ ਜੋ expired locks ਨੂੰ ਪਹਿਚਾਣਨ ਵਿੱਚ ਮਦਦ ਕਰੇ: `(locked_until)`\n- ਵਿਕਲਪਿਕ: active work ਲਈ partial index (ਉਦਾਹਰਨ ਲਈ, status `queued` ਅਤੇ `failed`)\n\nਇਹ "ਅਗਲਾ runnable job ਲੱਭੋ" ਕੁਏਰੀ ਨੂੰ ਤੇਜ਼ ਰੱਖਦੇ ਹਨ ਭਾਵੇਂ ਟੇਬਲ ਵੱਡੀ ਹੋ ਜਾਏ।\n\n## ਸੁਰੱਖਿਅਤ ਤਰੀਕੇ ਨਾਲ jobs claim ਅਤੇ locking\n\nਲਕਸ਼ਯ ਸਧਾਰਨ ਹੈ: ਬਹੁਤWorkers ਚਲ ਸਕਦੇ ਹਨ, ਪਰ ਸਿਰਫ਼ ਇੱਕ ਨੂੰ ਹੀ ਇੱਕ ਖਾਸ job ਲੈਣਾ ਚਾਹੀਦਾ ਹੈ। ਜੇ ਦੋ workers ਇੱਕੋ row ਨੂੰ process ਕਰ ਲੈਂਦੇ ਹਨ, ਤਾਂ ਤੁਸੀਂ double emails, double charges, ਜਾਂ ਗੰਦੇ ਡਾਟਾ ਪਾਉਂਗੇ।\n\nਇੱਕ ਸੁਰੱਖਿਅਤ ਤਰੀਕਾ job claim ਨੂੰ ਇੱਕ “lease” ਵਾਂਗ ਵਰਤਣਾ ਹੈ। Worker job ਨੂੰ ਇੱਕ ਛੋਟੇ ਸਮੇਂ ਲਈ locked ਕਰਦਾ ਹੈ। ਜੇ worker crash ਹੋ ਜਾਂਦਾ ਹੈ, ਤਾਂ lease expire ਹੋ ਜਾਂਦੀ ਹੈ ਅਤੇ ਦੂਜਾ worker ਉਹਨੂੰ ਲੈ ਸਕਦਾ ਹੈ। ਇਹੀ ਕਾਰਨ `locked_until` ਹੈ।\n\n### crashes ਸਦਾ ਕੰਮ ਨੂੰ ਰੋਕਣ ਨਾ ਕਰਨ ਲਈ lease ਦੀ ਵਰਤੋਂ ਕਰੋ\n\nਬਿਨਾਂ lease ਦੇ, ਇੱਕ worker job ਨੂੰ lock ਕਰਕੇ ਕਦੇ unlock ਨਹੀਂ ਕਰ ਸਕਦਾ (process kill ਹੋਈ, ਸਰਵਰ reboot, deploy ਗਲਤ ਹੋ ਗਿਆ)। `locked_until` ਨਾਲ job ਸਮੇਂ ਬਾਅਦ ਦੁਬਾਰਾ ਉਪਲਬਧ ਹੋ ਜਾਂਦੀ ਹੈ।\n\nਆਮ ਨਿਯਮ: ਇੱਕ job ਨੂੰ claim ਕੀਤਾ ਜਾ ਸਕਦਾ ਹੈ ਜਦੋਂ `locked_until` `NULL` ਹੋਵੇ ਜਾਂ `locked_until \u003c= now()` ਹੋਵੇ।\n\n### jobs ਨੂੰ atomic update ਨਾਲ claim ਕਰੋ\n\nਮੁੱਖ ਵਿਸ਼ੇਸ਼ਤਾ ਇਹ ਹੈ ਕਿ job claim ਇੱਕ single statement (ਜਾਂ ਇੱਕ transaction) ਵਿੱਚ ਹੋਵੇ। ਤੁਸੀਂ ਚਾਹੁੰਦੇ ਹੋ ਕਿ ਡੇਟਾਬੇਸ ਰੈਫਰੀ ਹੋਵੇ।\n\nਇਥੇ ਇੱਕ ਆਮ PostgreSQL ਪੈਟਰਨ ਹੈ: ਇੱਕ due job ਚੁਣੋ, ਇਸਨੂੰ lock ਕਰੋ, ਅਤੇ worker ਨੂੰ ਵਾਪਸ ਕਰੋ। (ਇਹ ਉਦਾਹਰਨ ਇੱਕ single `jobs` ਟੇਬਲ ਵਰਤਦੀ ਹੈ; ਉਹੀ ਵਿਚਾਰ `job_runs` ਤੋਂ claim ਕਰਨ ’ਤੇ ਲਾਗੂ ਹੁੰਦਾ ਹੈ.)\n\n```sql\nWITH next_job AS (\n SELECT id\n FROM jobs\n WHERE status = 'queued'\n AND run_at \u003c= now()\n AND (locked_until IS NULL OR locked_until \u003c= now())\n ORDER BY run_at ASC\n LIMIT 1\n FOR UPDATE SKIP LOCKED\n)\nUPDATE jobs j\nSET status = 'running',\n locked_until = now() + interval '2 minutes',\n locked_by = $1,\n attempts = attempts + 1,\n updated_at = now()\nFROM next_job\nWHERE j.id = next_job.id\nRETURNING j.*;\n```\n\nਕਿਉਂ ਇਹ ਕੰਮ ਕਰਦਾ ਹੈ:\n\n- `FOR UPDATE SKIP LOCKED` ਬਹੁਤWorkers ਨੂੰ ਮੁਕਾਬਲਾ ਕਰਨ ਦਿੰਦਾ ਹੈ ਬਿਨਾਂ ਇਕ-ਦੂਜੇ ਨੂੰ ਬਲਾਕ ਕੀਤੇ।\n- lease claim ਸਮੇਂ ਸੈੱਟ ਹੁੰਦੀ ਹੈ, ਤਾਂਕੇ ਹੋਰ workers ਇਸ ਨੂੰ expiry ਤੱਕ ਨਜ਼ਰਅੰਦਾਜ਼ ਕਰਦੇ ਹਨ।\n- `RETURNING` ਉਸ ਪਰਤ ਨੂੰ worker ਨੂੰ ਦੇ ਦਿੰਦਾ ਹੈ ਜਿਸ ਨੇ race ਜਿੱਤੀ।\n\n### lease ਕਿੰਨੀ ਲੰਬੀ ਹੋਣੀ ਚਾਹੀਦੀ ਹੈ, ਅਤੇ ਕਿਵੇਂ renew ਕਰਨੀ ਹੈ?\n\nlease ਨੂੰ ਤੁਹਾਡੇ ਆਮ run ਤੋਂ ਲੰਮਾ ਰੱਖੋ, ਪਰ ਇਸ ਤਰ੍ਹਾਂ ਛੋਟਾ ਰੱਖੋ ਕਿ ਇੱਕ crash ਜਲਦੀ recover ਹੋ ਜਾਵੇ। ਜੇ ਅਧਿਕਤਰ jobs 10 ਸਕਿੰਟ ਵਿੱਚ ਖਤਮ ਹੁੰਦੇ ਹਨ, ਤਾਂ 2 ਮਿੰਟ ਦਾ lease ਕਾਫ਼ੀ ਹੈ।\n\nਲੰਬੇ ਕੰਮਾਂ ਲਈ, ਕੰਮ ਕਰਦਿਆਂ lease renew (heartbeat) ਕਰੋ। ਆਮ ਤੌਰ 'ਤੇ: ਹਰ 30 ਸਕਿੰਟ ਮਧੀਨ `locked_until` ਵਧਾਓ ਜੇ ਤੁਸੀਂ ਅਜੇ ਵੀ job ਦੇ ਮਾਲਕ ਹੋ।\n\n- Lease ਦੀ ਲੰਬਾਈ: ਤੁਹਾਡੇ ਆਮ job ਸਮੇਂ ਦਾ 5x ਤੋਂ 20x\n- Heartbeat interval: lease ਦਾ 1/4 ਤੋਂ 1/2\n- Renewal update ਵਿੱਚ `WHERE id = $job_id AND locked_by = $worker_id` ਸ਼ਾਮਲ ਕਰੋ\n\nਇਹ ਆਖਰੀ ਸ਼ਰਤ ਮਹੱਤਵਪੂਰਣ ਹੈ। ਇਹ ਰੋਕਦੀ ਹੈ ਕਿ ਕੋਈ worker ਕਿਸੇ job ਨੂੰ extend ਕਰੇ ਜਿਸ ਦਾ ਉਹ ਹੁਣ ਮਾਲਕ ਨਹੀਂ।\n\n## retries ਅਤੇ backoff ਜੋ ਪੈਟਰਨ ਅਨੁਸਾਰ ਵਰਤਦੇ ਹਨ\n\nRetries ਉਹ ਜਗ੍ਹਾ ਹੈ ਜਿੱਥੇ ਇਹ ਪੈਟਰਨ ਸ਼ਾਂਤ ਮਹਿਸੂਸ ਕਰਦੈ ਜਾਂ ਸ਼ੋਰਮਚਾਉਣ ਵਾਲਾ ਬਣ ਜਾਂਦਾ ਹੈ। ਲਕਸ਼ਯ ਸਧਾਰਨ ਹੈ: ਜਦੋਂ ਕੋਈ job fail ਕਰਦਾ ਹੈ, ਤਾਂ ਦੁਬਾਰਾ ਇਕ ਸਮਝਦਾਰ ਤਰੀਕੇ ਨਾਲ ਬਾਅਦ ਵਿੱਚ ਕੋਸ਼ਿਸ਼ ਕਰੋ, ਜਿਸਨੂੰ ਤੁਸੀਂ ਵਿਆਖਿਆ ਕਰ ਸਕੋ, ਮਾਪ ਸਕੋ ਅਤੇ ਰੋਕ ਸਕੋ।\n\nਸਭ ਤੋਂ ਪਹਿਲਾਂ job state ਨਿਰਧਾਰਤ ਅਤੇ finite ਬਣਾਓ: `queued`, `running`, `succeeded`, `failed`, `dead`। ਅਮਲੀ ਤੌਰ 'ਤੇ, ਜ਼ਿਆਦਾਤਰ ਟੀਮਾਂ `failed` ਨੂੰ “ਫੇਲ ਹੋਇਆ ਪਰ ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕੀਤਾ ਜਾਵੇਗਾ” ਅਤੇ `dead` ਨੂੰ “ਫੇਲ ਹੋਇਆ ਅਤੇ ਅਸੀਂ ਹਾਰ ਮੰਨ ਲਈ” ਵਜੋਂ ਵਰਤਦੀਆਂ ਹਨ। ਇਹ ਇਕਫਰਕ ਅਨੰਤ ਲੂਪ ਰੋਕਦਾ ਹੈ।\n\nAttempt counting ਦੂਜਾ ਗਾਰਡਰੇਲ ਹੈ। `attempts` (ਕਿੰਨੀ ਵਾਰੀ ਕੋਸ਼ਿਸ਼ ਕੀਤੀ) ਅਤੇ `max_attempts` (ਕਿੰਨੀ ਵਾਰੀ ਆਗਿਆ ਹੈ) ਸਟੋਰ ਕਰੋ। ਜਦੋਂ worker ਇੱਕ error ਫੜਦਾ ਹੈ, ਇਹਨੂੰ ਕਰਨਾ ਚਾਹੀਦਾ ਹੈ:\n\n- `attempts` ਵਧਾਓ\n- ਜੇ `attempts \u003c max_attempts` ਤਾਂ state ਨੂੰ `failed` ਸੈੱਟ ਕਰੋ, ਨਹੀਂ ਤਾਂ `dead`\n- ਅਗਲੀ ਕੋਸ਼ਿਸ਼ ਲਈ `run_at` ਗਣਨਾ ਕਰੋ (ਸਰਫ਼ `failed` ਲਈ)\n\nBackoff ਸਿਰਫ਼ ਨਿਯਮ ਹੈ ਜੋ ਅਗਲਾ `run_at` ਨਿਰਧਾਰਤ ਕਰਦਾ ਹੈ। ਇੱਕ ਚੁਣੋ, ਦਸਤਾਵੇਜ਼ ਬਣਾਓ, ਅਤੇ ਸਥਿਰ ਰੱਖੋ:\n\n- Fixed delay: ਹਮੇਸ਼ਾ 1 ਮਿੰਟ ਦੂਰ\n- Exponential: 1m, 2m, 4m, 8m\n- Exponential with a cap: exponential ਪਰ ਕਦੇ ਵੀ 30m ਤੋਂ ਜ਼ਿਆਦਾ ਨਹੀਂ\n- Jitter ਜੋੜੋ: ਥੋੜ੍ਹਾ randomize ਕਰੋ ਤਾਂ ਜੋ ਸਾਰੇ jobs ਇੱਕੋ ਸਕਿੰਟ 'ਤੇ retry ਨਾ ਕਰਨ\n\nJitter ਉਸ ਵੇਲੇ ਮਹੱਤਵਪੂਰਣ ਹੁੰਦਾ ਹੈ ਜਦੋਂ ਕੋਈ dependency ਡਾਊਨ ਹੋ ਕੇ ਵਾਪਸ ਆਉਂਦੀ ਹੈ। ਬਿਨਾਂ ਇਸ ਦੇ, ਸੈਂਕੜੇ jobs ਇਕੱਠੇ retry ਕਰਕੇ ਫੇਰ ਫੇਲ ਹੋ ਸਕਦੇ ਹਨ।\n\nਫੇਲਯੋਗੀਆਂ ਨੂੰ ਡੀਬੱਗ ਕਰਨ ਲਈ ਕਾਫ਼ੀ error detail ਸਟੋਰ ਕਰੋ। ਤੁਹਾਨੂੰ ਪੂਰਾ logging ਸਿਸਟਮ ਦੀ ਲੋੜ ਨਹੀਂ, ਪਰ ਬੁਨਿਆਦੀ ਚੀਜ਼ਾਂ ਹਨ:\n\n- `last_error` (ਛੋਟੀ ਸੁਨੇਹਾ, admin ਸਕ੍ਰੀਨ 'ਤੇ ਦਿਖਾਉਣ ਲਈ ਸੁਰੱਖਿਅਤ)\n- `error_code` ਜਾਂ `error_type` (ਗਰੂਪਿੰਗ ਵਿੱਚ ਮਦਦ)\n- `failed_at` ਅਤੇ `next_run_at`\n- ਵਿਕਲਪਿਕ `last_stack` (ਜੇ ਤੁਸੀਂ ਆਕਾਰ ਸਮਭਾਲ ਸਕਦੇ ਹੋ)\n\nਇੱਕ ਠੋਸ ਨਿਯਮ ਜੋ ਵਧੀਆ ਕੰਮ ਕਰਦਾ ਹੈ: jobs ਨੂੰ 10 ਕੋਸ਼ਿਸ਼ਾਂ ਤੋਂ ਬਾਅਦ `dead` ਮਾਰਕ ਕਰੋ, ਅਤੇ exponential backoff ਨਾਲ jitter ਰੱਖੋ। ਇਹ ਟਰਾਂਜ਼ੀਐਂਟ ਫੇਲਯੋਗੀਆਂ ਨੂੰretry ਕਰਨ ਦਿੰਦਾ ਹੈ, ਪਰ ਟੁੱਟੇ ਹੋਏ jobs ਨੂੰ ਲਗਾਤਾਰ CPU ਖਰਚਣ ਤੋਂ ਰੋਕਦਾ ਹੈ।\n\n## Idempotency: duplicates ਨੂੰ ਰੋਕਣਾ ਜਦੋਂ job ਦੁਬਾਰਾ ਚਲਾਇਆ ਜਾਵੇ\n\nIdempotency ਦਾ ਮਤਲਬ ਹੈ ਕਿ ਤੁਹਾਡਾ job ਦੋ ਵਾਰੀ ਚਲਾਇਆ ਜਾਵੇ ਅਤੇ ਫਿਰ ਵੀ ਉਹੀ ਅੰਤਿਮ ਨਤੀਜਾ ਦੇਵੇ। ਇਸ ਪੈਟਰਨ ਵਿੱਚ ਇਹ ਮਹੱਤਵਪੂਰਣ ਹੈ ਕਿਉਂਕਿ ਇੱਕੋ row ਮੁੜ ਚੁਣਿਆ ਜਾ ਸਕਦਾ ਹੈ crash, timeout ਜਾਂ retry ਕਾਰਨ। ਜੇ ਤੁਹਾਡਾ job "invoice email ਭੇਜੋ" ਹੈ, ਤਾਂ ਇਹ ਦੋ ਵਾਰੀ ਚਲਾਉਣਾ ਨਿਰਪੱਖ ਨਹੀਂ ਹੈ।\n\nਅਮਲੀ ਸੋਚ ਇਹ ਹੈ: ਹਰ job ਨੂੰ (1) ਕੰਮ ਕਰਨਾ ਅਤੇ (2) ਪ੍ਰਭਾਵ ਲਗਾਉਣਾ ਵਿੱਚ ਵੰਡੋ। ਪ੍ਰਭਾਵ ਨੂੰ ਇੱਕ ਵਾਰੀ ਹੋਣਾ ਚਾਹੀਦਾ ਹੈ, ਚਾਹੇ ਕੰਮ ਕਈ ਵਾਰ ਕੋਸ਼ਿਸ਼ ਕੀਤੀ ਜਾਵੇ।\n\n### ਵਪਾਰਕ ਘਟਨਾ ਨਾਲ ਜੁੜਿਆ idempotency key ਵਰਤੋ\n\nIdempotency key ਉਸ ਚੀਜ਼ ਤੋਂ ਆਉਣਾ ਚਾਹੀਦਾ ਹੈ ਜੋ job ਦਰਸਾਉਂਦਾ ਹੈ, worker ਦੀ ਕੋਸ਼ਿਸ਼ ਤੋਂ ਨਹੀਂ। ਚੰਗੇ ਕੀ stable ਅਤੇ ਆਸਾਨ ਹੋਵਣਗੇ, ਜਿਵੇਂ `invoice_id`, `user_id + day`, ਜਾਂ `report_name + report_date`। ਜੇ ਦੋ ਕੋਸ਼ਿਸ਼ਾਂ ਇੱਕੋ ਹਕੀਕਤੀ ਘਟਨਾ ਨਾਲ ਸਬੰਧਿਤ ਹਨ, ਉਹ ਇੱਕੋ key ਸਾਂਝੀਆਂ ਕਰਣ।\n\nਉਦਾਹਰਨ: “2026-01-14 ਲਈ daily sales report ਬਣਾਓ” ਲਈ `sales_report:2026-01-14` ਵਰਤ ਸਕਦੇ ਹੋ। “Invoice 812 charge ਕਰੋ” ਲਈ `invoice_charge:812` ਵਰਤੋ।\n\n### ਡੇਟਾਬੇਸ constraints ਨਾਲ “ਕੇਵਲ ਇੱਕ ਵਾਰੀ” ਲਾਗੂ ਕਰੋ\n\nਸਭ ਤੋਂ ਸਧਾਰਣ ਗਾਰਡਰੇਲ PostgreSQL ਨੂੰ duplicates reject ਕਰਨ ਦੇਣੀ ਹੈ। idempotency key ਨੂੰ ਕਿਸੇ ਸਥਾਨ 'ਤੇ ਸਟੋਰ ਕਰੋ ਜੋ ਇੰਡੈਕਸ ਕੀਤਾ ਜਾ ਸਕਦਾ ਹੈ, ਫਿਰ unique constraint ਜੋੜੋ।\n\n```sql\n-- Example: ensure one logical job/effect per business key\nALTER TABLE jobs\nADD COLUMN idempotency_key text;\n\nCREATE UNIQUE INDEX jobs_idempotency_key_uniq\nON jobs (idempotency_key)\nWHERE idempotency_key IS NOT NULL;\n```\n\nਇਸ ਨਾਲ ਇੱਕੋ key ਵਾਲੀਆਂ ਦੋ rows ਇੱਕੋ ਸਮੇਂ ਮੌਜੂਦ ਨਹੀਂ ਹੋ ਸਕਦੀਆਂ। ਜੇ ਤੁਹਾਡੀ ਡਿਜ਼ਾਈਨ ਵਿੱਚ ਕਈ rows ਦੀ ਆਗਿਆ ਹੈ (ਇਤਿਹਾਸ ਲਈ), ਤਾਂ uniqueness ਨੂੰ effects ਟੇਬਲ ਤੇ ਰੱਖੋ, ਜਿਵੇਂ `sent_emails(idempotency_key)` ਜਾਂ `payments(idempotency_key)`.\n\nਸਧਾਰਨ side effects ਜੋ ਰੋਕੇ ਜਾਣੇ ਚਾਹੀਦੇ ਹਨ:\n\n- Emails: `sent_emails` row with unique key ਬਣਾਓ ਭੇਜਣ ਤੋਂ ਪਹਿਲਾਂ, ਜਾਂ ਭੇਜਣ ਤੋਂ ਬਾਅਦ provider message id ਰਿਕਾਰਡ ਕਰੋ।\n- Webhooks: `delivered_webhooks(event_id)` ਸਟੋਰ ਕਰੋ ਅਤੇ ਜੇ ਮੌਜੂਦ ਹੋਵੇ ਤਾਂ skip ਕਰੋ।\n- Payments: ਹਮੇਸ਼ਾ payment provider ਦੀ idempotency ਫੀਚਰ ਨਾਲ ਨਾਲ ਆਪਣਾ unique database key ਵਰਤੋ।\n- File writes: temp ਨਾਂ 'ਤੇ ਲਿਖੋ ਅਤੇ ਫਿਰ rename ਕਰੋ, ਜਾਂ `(type, date)` ਨਾਲ keyed `file_generated` record ਰੱਖੋ।\n\nਜੇ ਤੁਸੀਂ Postgres-backed stack (ਉਦਾਹਰਨ: Go + PostgreSQL) 'ਤੇ ਨਿਰਮਾਣ ਕਰ ਰਹੇ ਹੋ, ਤਾਂ ਇਹ uniqueness checks ਤੇਜ਼ ਅਤੇ ਡਾਟਾ ਦੇ ਨੇੜੇ ਰਹਿਣਗੇ। ਮੁੱਖ ਵਿਚਾਰ ਸਧਾਰਨ ਹੈ: retries ਸਧਾਰਨ ਹਨ, duplicates optional ਹਨ।\n\n## ਕਦਮ-ਦਰ-कਦਮ: ਇੱਕ ਘੱਟੋ-ਘੱਟ worker ਅਤੇ scheduler ਬਣਾਓ\n\nਇੱਕ ਰੁਟਿਨ runtime ਲੋ ਅਤੇ ਉਸ 'ਤੇ ਟਿਕੇ ਰਹੋ। ਕਰੋਨ + ਡੇਟਾਬੇਸ ਪੈਟਰਨ ਦਾ ਮਕਸਦ ਘੱਟ moving parts ਹੈ, ਸੋ ਇੱਕ ਛੋਟਾ Go, Node, ਜਾਂ Python ਪ੍ਰੋਸੈਸ ਜੋ PostgreSQL ਨਾਲ ਗੱਲ ਕਰਦਾ ਹੈ ਆਮ ਤੌਰ 'ਤੇ ਕਾਫ਼ੀ ਹੁੰਦਾ ਹੈ।\n\n### ਪੰਜ ਛੋਟੇ ਕਦਮਾਂ ਵਿੱਚ ਬਣਾਓ\n\n1) **ਟੇਬਲਾਂ ਅਤੇ ਇੰਡੈਕਸ ਬਣਾਓ।** ਇੱਕ `jobs` ਟੇਬਲ (ਅਤੇ ਬਾਅਦ ਲਈ ਕੋਈ_LOOKUP ਟੇਬਲ) ਜੋੜੋ, ਫਿਰ `run_at` ਤੇ ਇੰਡੈਕਸ ਕਰੋ, ਅਤੇ ਇੱਕ ਇੰਡੈਕਸ ਜੋ worker ਨੂੰ ਉਪਲਬਧ jobs ਤੇਜ਼ੀ ਨਾਲ ਲੱਭਣ ਵਿੱਚ ਮਦਦ ਕਰੇ (ਉਦਾਹਰਨ ਲਈ `(status, run_at)`).\n\n2) **ਛੋਟਾ enqueue ਫੰਕਸ਼ਨ ਲਿਖੋ।** ਤੁਹਾਡੀ ਐਪ ਇੱਕ row insert ਕਰੇ ਜਿਸ 'ਚ `run_at` ਨੂੰ “now” ਜਾਂ ਭਵਿੱਖ ਦਾ ਸਮਾਂ ਸੈੱਟ ਕੀਤਾ ਗਿਆ ਹੋਵੇ।payload ਛੋਟਾ ਅਤੇ ਪੇਸ਼ਾਨਾ ਰੱਖੋ (IDs ਅਤੇ job type, ਵੱਡੇ blobs ਨਹੀਂ)।\n\n```sql\nINSERT INTO jobs (type, payload, status, run_at, attempts, max_attempts)\nVALUES ($1, $2::jsonb, 'queued', $3, 0, 10);\n```\n\n3) **claim loop ਲਾਗੂ ਕਰੋ।** ਇਸਨੂੰ transaction ਵਿੱਚ ਚਲਾਓ। ਕੁਝ due jobs select ਕਰੋ, ਉਹਨਾਂ ਨੂੰ lock ਕਰੋ ਤਾਂਕਿ ਹੋਰ workers ਉਹਨਾਂ ਨੂੰ skip ਕਰਨ, ਅਤੇ ਇੱਕੋ transaction ਵਿੱਚ ਉਹਨਾਂ ਨੂੰ `running` ਸੈੱਟ ਕਰੋ।\n\n```sql\nWITH picked AS (\n SELECT id\n FROM jobs\n WHERE status = 'queued' AND run_at \u003c= now()\n ORDER BY run_at\n FOR UPDATE SKIP LOCKED\n LIMIT 10\n)\nUPDATE jobs\nSET status = 'running', started_at = now()\nWHERE id IN (SELECT id FROM picked)\nRETURNING *;\n```\n\n4) **Process ਅਤੇ finalize ਕਰੋ।** ਹਰ claimed job ਲਈ, ਕੰਮ ਕਰੋ, ਫਿਰ `done` ਵਿੱਚ update ਕਰੋ `finished_at` ਨਾਲ। ਜੇ ਫੇਲ ਹੁੰਦਾ ਹੈ, ਤਾਂ error message ਰਿਕਾਰਡ ਕਰੋ ਅਤੇ ਉਸ ਨੂੰ `queued` ਵਿੱਚ ਨਵਾਂ `run_at` (backoff) ਦੇ ਕੇ ਵਾਪਸ ਰੱਖੋ। finalization updates ਛੋਟੇ ਰੱਖੋ ਅਤੇ ਉਹਨਾਂ ਨੂੰ ਸਦਾ ਚਲਾਉ, ਭਾਵੇਂ ਤੁਹਾਡੀ ਪ੍ਰਕਿਰਿਆ shutting down ਹੋ ਰਹੀ ਹੋਵੇ।\n\n5) **retry ਨਿਯਮ ਜੋ ਤੁਸੀਂ ਸਮਝਾ ਸਕੋ ਜੋੜੋ।** ਇੱਕ ਸਧਾਰਨ ਫੌਰਮੂਲਾ ਵਰਤੋ ਜਿਵੇਂ `run_at = now() + (attempts^2) * interval '10 seconds'`, ਅਤੇ `max_attempts` ਤੋਂ ਬਾਅਦ `status = 'dead'` ਕਰ ਦਿਓ।\n\n### ਮੁੱਢਲੈ ਵਿਜ਼ੀਬਿਲਿਟੀ ਜੋੜੋ\n\nਦਿਨ-ਇੱਕ ਦਿਨ ਦਾ ਡੈਸ਼ਬੋਰਡ ਨਹੀਂ ਚਾਹੀਦਾ, ਪਰ ਤੁਹਾਨੂੰ ਸਮੱਸਿਆਵਾਂ ਨੋਟਿਸ ਕਰਨ ਲਈ ਕਾਫ਼ੀ ਚੀਜ਼ਾਂ ਚਾਹੀਦੀਆਂ ਹਨ।\n\n- ਹਰ job ਲਈ ਇਕ ਲਾਈਨ ਲੌਗ ਕਰੋ: claimed, succeeded, failed, retried, dead।\n- “dead jobs” ਅਤੇ “purane running jobs” ਲਈ ਇੱਕ ਸਧਾਰਨ admin query ਜਾਂ view ਬਣਾਓ।\n- counts 'ਤੇ alert ਜੋੜੋ (ਉਦਾਹਰਨ ਲਈ, ਪਿਛਲੇ ਘੰਟੇ ਵਿੱਚ N ਤੋਂ ਵੱਧ dead jobs)।\n\nਜੇ ਤੁਸੀਂ ਪਹਿਲਾਂ ਹੀ Go + PostgreSQL ਸਟੈਕ 'ਤੇ ਹੋ, ਇਹ ਇੱਕ single worker binary + cron ਨਾਲ ਸਾਫ਼ ਮੈਪ ਹੁੰਦਾ ਹੈ।\n\n## ਇੱਕ ਹਕੀਕਤੀ ਉਦਾਹਰਨ ਜੋ ਤੁਸੀਂ ਕਾਪੀ ਕਰ ਸਕਦੇ ਹੋ\n\nਕਲਪਨਾ ਕਰੋ ਇੱਕ ਛੋਟੀ SaaS ਐਪ ਜਿਸ ਨੇ ਦੋ scheduled ਕੰਮ ਹਨ:\n\n- ਇੱਕ ਰਾਤੀ cleanup ਜੋ expired sessions ਅਤੇ ਪੁਰਾਣੀਆਂ temporary files ਹਟਾਉਂਦਾ ਹੈ।\n- ਇੱਕ ਹਫਤਾਵਾਰੀ “ਤੁਹਾਡੀ activity report” ਈਮੇਲ ਜੋ ਹਰ ਸੋਮਵਾਰ ਸਵੇਰੇ ਹਰ ਯੂਜ਼ਰ ਨੂੰ ਭੇਜੀ ਜਾਂਦੀ ਹੈ।\n\nਸਰਲ ਰੱਖੋ: jobs ਨੂੰ ਰੱਖਣ ਲਈ ਇੱਕ PostgreSQL ਟੇਬਲ, ਅਤੇ ਹਰ ਮਿੰਟ ਚਲਣ ਵਾਲਾ ਇੱਕ worker (cron ਦੁਆਰਾ trigger)। Worker due jobs claim ਕਰਦਾ ਹੈ, ਉਹਨਾਂ ਨੂੰ ਚਲਾਉਂਦਾ ਹੈ, ਅਤੇ success ਜਾਂ failure ਰਿਕਾਰਡ ਕਰਦਾ ਹੈ।\n\n### ਕੀ enqueue ਹੁੰਦਾ ਹੈ, ਅਤੇ ਕਦੋਂ\n\nਤੁਸੀਂ jobs ਕਈ ਥਾਵਾਂ ਤੋਂ enqueue ਕਰ ਸਕਦੇ ਹੋ:\n\n- ਹਰ ਰੋਜ਼ 02:00 ਤੇ: ਇੱਕ `cleanup_nightly` job enqueue ਕਰੋ “ਉਸ ਦਿਨ” ਲਈ।\n- ਸਾਈਨਅਪ 'ਤੇ: ਇੱਕ `send_weekly_report` job ਉਸ ਯੂਜ਼ਰ ਦੇ ਅਗਲੇ ਸੋਮਵਾਰ ਲਈ enqueue ਕਰੋ।\n- ਕਿਸੇ ਘਟਨਾ ਤੋਂ ਬਾਅਦ (ਜਿਵੇਂ “ਯੂਜ਼ਰ ਨੇ Export report ਕਲਿੱਕ ਕੀਤਾ”): ਇੱਕ `send_weekly_report` job instantaneous ਤੌਰ ਤੇ ਇੱਕ ਨਿਰਧਾਰਤ date range ਲਈ enqueue ਕਰੋ।\n\npayload ਸਿਰਫ਼ ਘੱਟੋ-ਘੱਟ ਜਾਣਕਾਰੀ ਰੱਖੋ ਜੋ worker ਨੂੰ ਚਾਹੀਦੀ ਹੈ। ਇਸਨੂੰ ਛੋਟਾ ਰੱਖੋ ਤਾਂ retry ਆਸਾਨ ਹੋਵੇ।\n\n```json\n{\n "type": "send_weekly_report",\n "payload": {\n "user_id": 12345,\n "date_range": {\n "from": "2026-01-01",\n "to": "2026-01-07"\n }\n }\n}\n```\n\n### idempotency ਕਿਵੇਂ double sending ਰੋਕਦੀ ਹੈ\n\nWorker ਸਭ ਤੋਂ ਖਰਾਬ ਪਲ 'ਤੇ crash ਕਰ ਸਕਦਾ ਹੈ: ਈਮੇਲ ਭੇਜਣ ਤੋਂ ਬਾਅਦ ਪਰ job ਨੂੰ “done” ਨਾਲ ਮਾਰਕ ਕਰਨ ਤੋਂ ਪਹਿਲਾਂ। ਜਦੋਂ ਇਹ restart ਹੁੰਦਾ ਹੈ, ਇਹ ਇਕੋ job ਮੁੜ ਚੁਣ ਸਕਦਾ ਹੈ।\n\nDuplicate-sends ਰੋਕਣ ਲਈ, ਕੰਮ ਨੂੰ ਇੱਕ ਕੁਦਰਤੀ dedupe key ਦਿਓ ਅਤੇ ਉਹ record ਐਸੇ ਥਾਂ ਰੱਖੋ ਜਿੱਥੇ ਡੇਟਾਬੇਸ enforce ਕਰ ਸਕੇ। weekly reports ਲਈ, ਚੰਗਾ key ਹੈ `(user_id, week_start_date)`. ਭੇਜਣ ਤੋਂ ਪਹਿਲਾਂ worker “ਮੈਂ report X ਭੇਜਣ ਵਾਲਾ ਹਾਂ” ਰਿਕਾਰਡ ਕਰਦਾ ਹੈ। ਜੇ ਉਹ record ਪਹਿਲਾਂ ਹੀ ਮੌਜੂਦ ਹੋਵੇ ਤਾਂ skip ਕਰੋ।\n\nਇਹ ਸਿੱਧਾ `sent_reports` ਟੇਬਲ ਨਾਲ ਹੁੰਦਾ ਹੈ ਜਿਸ 'ਤੇ `(user_id, week_start_date)` 'ਤੇ unique constraint ਹੋਵੇ, ਜਾਂ job ਖੁਦ `idempotency_key` ਰੱਖੇ।\n\n### ਇੱਕ failure ਕਿਵੇਂ ਦਿਸਦਾ ਹੈ (ਅਤੇ ਕਿਵੇਂ recover ਹੁੰਦਾ ਹੈ)\n\nਮਾਨ ਲਓ ਤੁਹਾਡਾ email provider timeout ਦੇ ਦਿੰਦਾ ਹੈ। job fail ਹੋ ਜਾਂਦਾ ਹੈ, ਇਸ ਲਈ worker:\n\n- `attempts` ਵਧਾਉਂਦਾ ਹੈ\n- debugging ਲਈ error message ਸੇਵ ਕਰਦਾ ਹੈ\n- backoff ਨਾਲ ਅਗਲੀ ਕੋਸ਼ਿਸ਼ ਸ਼ਡਿਊਲ ਕਰਦਾ ਹੈ (ਉਦਾਹਰਨ: +1 ਮਿੰਟ, +5 ਮਿੰਟ, +30 ਮਿੰਟ, +2 ਘੰਟੇ)\n\nਜੇ ਇਹ ਤੁਹਾਡੇ limit (ਜਿਵੇਂ 10 attempts) ਤੋਂ ਬਾਅਦ ਵੀ fail ਕਰਦਾ ਹੈ, ਤਾਂ ਇਸਨੂੰ `dead` ਮਾਰਕ ਕਰੋ ਅਤੇ retry ਰੋਕ ਦਿਓ। job ਜਾਂ ਤਾਂ ਇਕ ਵਾਰੀ ਸਫਲ ਹੋਵੇਗਾ, ਜਾਂ ਇਹ ਇੱਕ ਸਪਸ਼ਟ ਸ਼ਡਿਊਲ 'ਤੇ retry ਕਰੇਗਾ, ਅਤੇ idempotency retry ਨੂੰ ਸੁਰੱਖਿਅਤ ਬਣਾਏਗਾ।\n\n## ਆਮ ਗਲਤੀਆਂ ਅਤੇ ਫਸਣਾ ਵਾਲੀਆਂ ਜਗ੍ਹਾਂ\n\nਕਰੋਨ + ਡੇਟਾਬੇਸ ਪੈਟਰਨ ਸਧਾਰਨ ਹੈ, ਪਰ ਛੋਟੀਆਂ ਗਲਤੀਆਂ ਇਸਨੂੰ duplicates, stuck work, ਜਾਂ ਅਚਾਨਕ load ਵਿੱਚ ਬਦਲ ਸਕਦੀਆਂ ਹਨ। ਅਕਸਰ ਸਮੱਸਿਆਵਾਂ ਪਹਿਲੇ crash, deploy, ਜਾਂ traffic spike ਤੋਂ ਬਾਅਦ ਆਉਂਦੀਆਂ ਹਨ।\n\n### duplicates ਜਾਂ stuck jobs ਪੈਦਾ ਕਰਨ ਵਾਲੀਆਂ ਗਲਤੀਆਂ\n\nਜ਼ਿਆਦਾਤਰ ਹਕੀਕਤੀ ਘਟਨਾਵਾਂ ਕੁਝ ਜਾਲਾਂ ਤੋਂ ਆਉਂਦੀਆਂ ਹਨ:\n\n- ਉਹੀ job ਵੱਖ-ਵੱਖ cron entries ਤੋਂ ਚਲਾਉਣਾ ਬਿਨਾਂ lease ਦੇ। ਜੇ ਦੋ ਸਰਵਰ ਇੱਕੋ ਮਿੰਟ 'ਤੇ ਟਿਕ ਕਰਦੇ ਹਨ, ਦੋਹਾਂ ਇੱਕੋ ਕੰਮ claim ਕਰ ਸਕਦੇ ਹਨ ਜਦ ਤੱਕ ਤੁਸੀਂ claim step atomic ਨਹੀਂ ਬਣਾਉਂਦੇ ਅਤੇ ਇੱਕੋ ਹੀ transaction ਵਿੱਚ lock (ਜਾਂ lease) ਸੈੱਟ ਨਹੀਂ ਕਰਦੇ।\n- `locked_until` ਨੂੰ ਛੱਡ ਦਿਤਾ ਗਿਆ। ਜੇ worker claim ਕਰਨ ਤੋਂ ਬਾਅਦ crash ਹੋ ਜਾਂਦਾ ਹੈ, ਤਾਂ row "in progress" ਅਨੰਤਕਾਲ ਲਈ ਰਹਿ ਸਕਦੀ ਹੈ। lease timestamp ਦੂਜੇ worker ਨੂੰ ਬਾਅਦ ਵਿੱਚ safely ਚੁਣਨ ਦਿੰਦੀ ਹੈ।\n- failure 'ਤੇ ਤੁਰੰਤ retry ਕਰਨਾ। ਜਦੋਂ ਕੋਈ API ਡਾਊਨ ਹੋਵੇ, ਤੁਰੰਤ retries spikes ਬਣਾਉਂਦੇ ਹਨ, rate limits ਖਰਚ ਕਰਦੇ ਹਨ, ਅਤੇ ਲਗਾਤਾਰ fail ਹੁੰਦੇ ਰਹਿੰਦੇ ਹਨ। ਹਮੇਸ਼ਾ ਅਗਲੀ ਕੋਸ਼ਿਸ਼ ਨੂੰ ਭਵਿੱਖ ਵਿੱਚ schedule ਕਰੋ।\n- “at least once” ਨੂੰ “exactly once” ਸਮਝਣਾ। ਇੱਕ job ਦੁਬਾਰਾ ਚਲ ਸਕਦੀ ਹੈ (timeouts, worker restarts, network issues)। ਜੇ ਦੋ ਵਾਰੀ ਚਲਣਾ ਨੁਕਸਾਨਦੇਹ ਹੈ, ਤਾਂ side effects ਨੂੰ repeat-safe ਬਣਾਓ।\n- job row ਵਿੱਚ ਵੱਡੇ payloads ਰੱਖਣਾ। ਵੱਡੇ JSON blobs ਟੇਬਲ ਨੂੰ ਫੂਲ੍ਹਾ ਦਿੰਦੇ ਹਨ, indexes ਨੂੰ slow ਕਰਦੇ ਹਨ, ਅਤੇ locking ਨੂੰ ਭਾਰੀ ਬਣਾਉਂਦੇ ਹਨ। ਇੱਕ ਸੰਦਰਭ (ਜਿਵੇਂ `user_id`, `invoice_id`, ਜਾਂ file key) ਰੱਖੋ ਅਤੇ ਰਨ ਹੋਣ 'ਤੇ ਬਾਕੀ ਲਿਆਓ।\n\nਉਦਾਹਰਨ: ਤੁਸੀਂ weekly invoice ਈਮੇਲ ਭੇਜਦੇ ਹੋ। ਜੇ worker ਭੇਜਣ ਤੋਂ ਬਾਅਦ timeout ਹੋ ਜਾਵੇ ਪਰ job ਨੂੰ done ਮਾਰਕ ਕਰਨ ਤੋਂ ਪਹਿਲਾਂ, ਤਾਂ ਇਕੋ job ਮੁੜ retry ਹੋ ਸਕਦੀ ਹੈ ਅਤੇ duplicate ਈਮੇਲ ਜਨਮ ਲੈ ਸਕਦਾ ਹੈ। ਇਹ ਇਸ ਪੈਟਰਨ ਲਈ ਸਧਾਰਨ ਹੈ ਜਦ ਤੱਕ ਤੁਸੀਂ ਇੱਕ ਗਾਰਡਰੇਲ ਨਹੀਂ ਜੋੜਦੇ (ਉਦਾਹਰਨ ਲਈ, `invoice_id` ਤੇ keyed "email sent" event)\n\n### ਘੱਟ-ਸਪੱਸ਼ਟ ਗੋਟਚਾਸ\n\nਲੰਮੇ transaction ਵਿੱਚ scheduling ਅਤੇ execution ਮਿਲਾਉਣ ਤੋਂ ਬਚੋ। ਜੇ ਤੁਸੀਂ network calls ਦੌਰਾਨ transaction ਖੋਲ੍ਹੇ ਰੱਖਦੇ ਹੋ, ਤਾਂ ਤੁਸੀਂ ਲਾਕਜ਼ ਨੂੰ ਜ਼ਰੂਰਤ ਤੋਂ ਲੰਬੇ ਸਮੇਂ ਲਈ ਰੱਖ ਲੈਂਦੇ ਹੋ ਅਤੇ ਹੋਰ workers ਨੂੰ ਬਲਾਕ ਕਰਦੇ ਹੋ।\n\nਮਸ਼ੀਨਾਂ ਵਿਚਕਾਰ ਘੜੀ ਫਰਕਾਂ ਲਈ ਸਾਵਧਾਨ ਰਹੋ। `run_at` ਅਤੇ `locked_until` ਲਈ database time (`NOW()` in PostgreSQL) ਕੋ ਸਰੋਤ ਅਸਲ ਸਮਾਂ ਮਾਨੋ, ਐਪ ਸਰਵਰ ਘੜੀ ਨਹੀਂ।\n\nਸਾਫ਼ maximum runtime ਸੈੱਟ ਕਰੋ। ਜੇ ਇੱਕ job 30 ਮਿੰਟ ਲੈ ਸਕਦਾ ਹੈ, ਤਾਂ lease ਉਸ ਤੋਂ ਵੱਧ ਰੱਖੋ, ਅਤੇ ਜਰੂਰਤ ਹੋਏ ਤਾਂ renew ਕਰੋ। ਨਹੀਂ ਤਾਂ ਕੋਈ ਹੋਰ worker ਉਸਨੂੰ ਚਲਦਿਆਂ beech ਵਿੱਚ ਲੈ ਸਕਦਾ ਹੈ।\n\nਆਪਣੀ jobs ਟੇਬਲ ਸਿਹਤਮੰਦ ਰੱਖੋ। ਜੇ ਪੂਰੇ ਹੋਏ jobs ਹਮੇਸ਼ਾ ਲਈ ਜਮ੍ਹੇ ਰਹਿਣ, queries slow ਹੋ ਜਾਂਦੀਆਂ ਅਤੇ lock contention ਵੱਧ ਜਾਂਦੀ ਹੈ। ਟੇਬਲ ਵੱਡਾ ਹੋ ਜਾਣ ਤੋਂ ਪਹਿਲਾਂ ਇਕ retention ਨੀਤੀ (archive ਜਾਂ delete) ਰੱਖੋ।\n\n## ਤੁਰੰਤ ਚੈੱਕਲਿਸਟ ਅਤੇ ਅਗਲੇ ਕਦਮ\n\n### ਤੁਰੰਤ ਚੈੱਕਲਿਸਟ\n\nਇਸ ਪੈਟਰਨ ਨੂੰ ship ਕਰਨ ਤੋਂ ਪਹਿਲਾਂ ਬੁਨਿਆਦੀ ਚੀਜ਼ਾਂ ਚੈਕ ਕਰੋ। ਇੱਥੇ ਇੱਕ ਛੋਟੀ ਚੁੱਕੀ ਗਲਤੀ ਅਕਸਰ stuck jobs, duplicate, ਜਾਂ database 'ਤੇ ਹਮਲੇ ਵਾਲੇ worker ਬਣਾਉਂਦੀ ਹੈ।\n\n- ਤੁਹਾਡੀ jobs ਟੇਬਲ ਵਿੱਚ ਲਾਜ਼ਮੀ ਚੀਜ਼ਾਂ ਹਨ: `run_at`, `status`, `attempts`, `locked_until`, ਅਤੇ `max_attempts` (ਨਾਲ `last_error` ਜਾਂ ਇਸੇ ਤਰ੍ਹਾਂ ਤਾਂਕਿ ਤੁਸੀਂ ਦੇਖ ਸਕੋ ਕਿ ਕੀ ਹੋਇਆ)।\n- ਹਰ job ਦੋ ਵਾਰੀ ਸੁਰੱਖਿਅਤ ਤਰੀਕੇ ਨਾਲ ਚਲ ਸਕਦਾ ਹੈ। ਜੇ ਤੁਸੀਂ ਪੱਕਾ ਨਹੀਂ ਹੋ, ਤਾਂ idempotency key ਜਾਂ side effect ਨੂੰ uniqueness rule ਸ਼ਾਮਲ ਕਰੋ (ਉਦਾਹਰਨ: `invoice_id` ਲਈ ਇੱਕ invoice).\n- ਫੇਲੀਆਂ ਨੂੰ ਦੇਖਣ ਅਤੇ ਫੈਸਲਾ ਕਰਨ ਲਈ ਇੱਕ ਸਪਸ਼ਟ ਥਾਂ ਹੈ: failed jobs ਦੇਖੋ, job ਨੂੰ ਦੁਬਾਰਾ ਚਲਾਓ, ਜਾਂ ਜਦੋਂ ਰੋਕਣਾ ਹੋਵੇ ਤਾਂ `dead` ਮਾਰਕ ਕਰੋ।\n- ਤੁਹਾਡੀ lease (lock) timeout ਕੰਮ ਲਈ ਸੰਹੀ ਹੈ। ਇਹ ਆਮ ਚਲਾਉਣ ਲਈ ਲੰਮਾ ਹੋਣਾ ਚਾਹੀਦਾ ਹੈ, ਪਰ crash ਹੋਏ workers ਨੂੰ ਘੰਟਿਆਂ ਲਈ ਰੋਕਣ ਲਈ ਛੋਟਾ।\n- Retry backoff ਪੇਸ਼ਾਨਾ ਹੈ। ਇਹ ਦੁਬਾਰਾ ਫੇਲਯੋਗੀਆਂ ਨੂੰ ਹੌਲੀ ਕਰਦਾ ਹੈ ਅਤੇ `max_attempts` ਤੋਂ ਬਾਅਦ ਰੁਕਦਾ ਹੈ।\n\nਜੇ ਇਹ ਸੱਚ ਹੈ, ਤਾਂ ਕਰੋਨ + ਡੇਟਾਬੇਸ ਪੈਟਰਨ ਅਕਸਰ ਹਕੀਕਤੀ ਵਰਕਲੋਡ ਲਈ ਕਾਫ਼ੀ ਸਥਿਰ ਰਹਿੰਦਾ ਹੈ।\n\n### ਅਗਲੇ ਕਦਮ\n\nਚੈੱਕਲਿਸਟ ਠੀਕ ਹੋਣ 'ਤੇ, ਰੋਜ਼ਾਨਾ ਓਪਰੇਸ਼ਨ 'ਤੇ ਧਿਆਨ ਦਿਓ।\n\n- ਦੋ ਛੋਟੇ admin actions ਜੋੜੋ: “retry now” (`run_at = now()` ਅਤੇ lock ਸਾਫ਼) ਅਤੇ “cancel” (terminal status ਵਿੱਚ ਭੇਜੋ)। ਇਨ੍ਹਾਂ ਨਾਲ incidents ਦੌਰਾਨ ਸਮਾਂ ਬਚਦਾ ਹੈ।\n- worker ਹਰ job ਲਈ ਇੱਕ ਲਾਈਨ ਲੌਗ ਕਰੇ: job type, job id, attempt number, ਅਤੇ result। growing failure counts 'ਤੇ alert ਜੋੜੋ।\n- ਇੱਕ ਹਕੀਕਤੀ spike ਨਾਲ load test ਕਰੋ: ਬਹੁਤ ਸਾਰੇ jobs ਇੱਕੋ ਮਿੰਟ ਲਈ schedule ਕੀਤੇ ਗਏ। ਜੇ claiming jobs slow ਹੁੰਦਾ ਹੈ, ਸਹੀ ਇੰਡੈਕਸ ਜੋੜੋ (ਅਕਸਰ `status, run_at`).\n\nਜੇ ਤੁਸੀਂ ਇਸ ਤਰ੍ਹਾਂ ਦੀ setup ਤੇਜ਼ੀ ਨਾਲ ਬਣਾਉਣਾ ਚਾਹੁੰਦੇ ਹੋ, ਤਾਂ Koder.ai (koder.ai) ਤੁਹਾਨੂੰ schema ਤੋਂ deployed Go + PostgreSQL ਐਪ ਤੱਕ ਘੱਟ manual ਵ੍ਹਾਇਰਿੰਗ ਨਾਲ ਮਦਦ ਕਰ ਸਕਦਾ ਹੈ, ਤਾਂ ਜੋ ਤੁਸੀਂ locking, retries, ਅਤੇ idempotency ਨੀਤੀਆਂ 'ਤੇ ਧਿਆਨ ਦੇ ਸਕੋ।\n\nਅਗਰ ਤੁਸੀਂ ਬਾਅਦ ਵਿੱਚ ਇਸ setup ਤੋਂ ਬਾਹਰ ਨਿਕਲਦੇ ਹੋ, ਤਾਂ ਤੁਸੀਂ job lifecycle ਨੂੰ ਸਾਫ਼ ਤਰੀਕੇ ਨਾਲ ਸਿੱਖ ਲਿਆ ਹੋਵੇਗਾ, ਅਤੇ ਉਹੀ ਵਿਚਾਰਾਂ ਪੂਰੇ queue ਸਿਸਟਮ ਨੂੰ ਮੈਪ ਕਰਨ ਵਿੱਚ ਮਦਦ ਕਰਨਗੇ। Cron + ਡੇਟਾਬੇਸ ਪੈਟਰਨ: queue ਦੇ ਬਿਨਾਂ scheduled ਬੈਕਗ੍ਰਾਊਂਡ ਜਾਬਸ | Koder.ai ਤੇ ਕੰਮ ਚਾਹੀਦਾ ਹੁੰਦਾ ਹੈ: follow-up ਈਮੇਲ ਭੇਜਣੇ, ਰਾਤ ਨੂੰ billing ਚੈੱਕ, ਪੁਰਾਣੇ record ਸਾਫ਼ ਕਰਨਾ, ਇੱਕ ਰਿਪੋਰਟ ਦੁਬਾਰਾ ਬਣਾਉਣਾ ਜਾਂ cache ਤਾਜ਼ਾ ਕਰਨਾ।\n\nਸ਼ੁਰੂ ਵਿੱਚ, ਪੂਰਾ queue ਸਿਸਟਮ ਸ਼ਾਮਲ ਕਰਨਾ ਲੁਭਾਵਣਾ ਹੁੰਦਾ ਹੈ ਕਿਉਂਕਿ ਇਹ background jobs ਦਾ “ਸਹੀ” ਤਰੀਕਾ ਲੱਗਦਾ ਹੈ। ਪਰ queue ਹੋਰ moving parts ਜੋੜਦਾ ਹੈ: ਇੱਕ ਹੋਰ ਸਰਵਿਸ ਚਲਾਉਣੀ, ਮੌਨੀਟਰ ਕਰਨਾਂ, ਡਿਪਲੋਏ ਕਰਨਾਂ ਅਤੇ ਡੀਬੱਗ ਕਰਨਾਂ। ਛੋਟੀ ਟੀਮ (ਜਾਂ ਇਕੱਲਾ ਫاؤنਡਰ) ਲਈ ਇਹ ਵਧੇਰਾ ਭਾਰ ਅਕਸਰ ਤੁਹਾਨੂੰ ਧੀਰਾ ਕਰ ਦਿੰਦਾ ਹੈ।\n\nਅਸਲ ਸਵਾਲ ਇਹ ਹੈ: ਤੁਸੀਂ ਵਧੇਰਾ ਇੰਨਫ੍ਰਾਸਟ੍ਰੱਕਚਰ ਬਣਾਏ ਬਿਨਾਂ scheduled ਕੰਮ ਕਿਵੇਂ ਭਰੋਸੇਯੋਗ ਢੰਗ ਨਾਲ ਚਲਾਓਗੇ?\n\nਇੱਕ ਆਮ ਪਹਿਲਾ ਯਤਨ ਸਧਾਰਨ ਹੁੰਦਾ ਹੈ: ਇੱਕ cron ਐਂਟਰੀ ਜੋ ਇੱਕ endpoint ਨੂੰ ਹਿੱਟ ਕਰਦੀ ਹੈ, ਅਤੇ ਉਹ endpoint ਕੰਮ ਕਰਦਾ ਹੈ। ਇਹ ਤਦ ਤੱਕ ਠੀਕ ਰਹਿੰਦਾ ਹੈ ਜਦ ਤੱਕ ਇਹ ਨਹੀ ਰੁਕਦਾ। ਜਦੋਂ ਤੁਹਾਡੇ ਕੋਲ ਇੱਕ ਤੋਂ ਵੱਧ ਸਰਵਰ ਹੁੰਦੇ ਹਨ, ਗਲਤ ਸਮੇਂ ਡਿਪਲੋਏ ਹੁੰਦਾ ਹੈ, ਜਾਂ ਕੋਈ job ਉਮੀਦ ਤੋਂ ਲੰਮਾ ਲੈਂਦੀ ਹੈ, ਤਾਂ ਤੁਸੀਂ ਅਜਿਹੀਆਂ ਹੇਠਾਂ ਦਿੱਤੀਆਂ ਸਮੱਸਿਆਵਾਂ ਵੇਖਦੇ ਹੋ।\n\nScheduled ਕੰਮ ਆਮ ਤੌਰ 'ਤੇ ਕੁਝ ਪੈਟਰਨਾਂ ਵਿੱਚ ਟੁੱਟਦਾ ਹੈ:\n\n- ਦੋਹਰਾ ਚਲਾਉਣਾ: ਦੋ ਸਰਵਰ ਇੱਕੋ ਹੀ ਟਾਸਕ ਚਲਾਉਂਦੇ ਹਨ, ਇਸ ਕਰਕੇ invoices ਦਫ਼ਤਾ ਰਜਿਸਟਰ ਹੋ ਜਾਂਦੇ ਹਨ ਜਾਂ ਈਮੇਲ ਦੋ ਵਾਰੀ ਭੇਜੇ ਜਾਂਦੇ ਹਨ।\n- ਗੁੰਮ ਹੋਏ ਚਲਾਉਣ: cron کال deploy ਦੌਰਾਨ ਫੇਲ ਹੋ ਜਾਂਦੀ ਹੈ ਅਤੇ ਕੋਈ ਨੋਟਿਸ ਨਹੀਂ ਲੈਂਦਾ ਜਦ ਤੱਕ ਵਰਤੋਂਕਾਰ ਸ਼ਿਕਾਇਤ ਨਾ ਕਰ ਦੇਣ।\n- ਖਾਮੋਸ਼ ਨਾਕਾਮੀਆਂ: job ਇੱਕ ਵਾਰੀ error ਦਿੰਦਾ ਹੈ ਤੇ ਫਿਰ ਕਦੇ ਨਹੀਂ ਚਲਦਾ ਕਿਉਂਕਿ ਕੋਈ retry ਯੋਜ਼ਨਾ ਨਹੀਂ।\n- ਅਧੂਰਾ ਕੰਮ: job ਅੱਧੇ ਰਾਹ 'ਤੇ crash ਹੋ ਕੇ ਡਾਟਾ ਨੂੰ ਅਜੀਬ ਹਾਲਤ ਵਿੱਚ ਛੱਡ ਦਿੰਦਾ ਹੈ।\n- ਕੋਈ ਆਡਿਟ ਟਰੇਲ ਨਹੀਂ: ਤੁਸੀਂ ਨਹੀਂ ਦੱਸ ਸਕਦੇ “ਇਹ ਆਖ਼ਰੀ ਵਾਰ ਕਦੋਂ ਚਲਿਆ?” ਜਾਂ “ਕੱਲ੍ਹ ਰਾਤ ਕੀ ਹੋਇਆ?”\n\nਕਰੋਨ + ਡੇਟਾਬੇਸ ਪੈਟਰਨ ਇਕ ਮੱਧਮਾਰਗ ਹੈ। ਤੁਸੀਂ ਹੁਣ ਵੀ cron ਨੂੰ schedule ਤੇ “ਉਠਾਉਣ” ਲਈ ਵਰਤਦੇ ਹੋ, ਪਰ ਤੁਸੀਂ job ਦੀ ਇਰਾਦਾ ਅਤੇ ਅਵਸਥਾ ਨੂੰ ਆਪਣੇ ਡੇਟਾਬੇਸ ਵਿੱਚ ਸਟੋਰ ਕਰਦੇ ਹੋ ਤਾਂ ਕਿ ਸਿਸਟਮ ਕੋਆਰਡੀਨੇਟ, retry, ਅਤੇ ਕੀ ਹੋਇਆ ਉਹ ਰਿਕਾਰਡ ਕਰ ਸਕੇ।\n\nਇਹ ਉਹਨਾਂ ਹਾਲਤਾਂ ਲਈ ਵਧੀਆ ਹੈ ਜਦੋਂ ਤੁਹਾਡੇ ਕੋਲ ਪਹਿਲਾਂ ਹੀ ਇੱਕ ਡੇਟਾਬੇਸ (ਅਕਸਰ PostgreSQL) ਹੈ, ਕਈ job ਕਿਸਮਾਂ ਘੱਟ ਹਨ, ਅਤੇ ਤੁਸੀਂ ਘੱਟ ops ਨਾਲ ਪੈਦਾ ਹੋਣ ਵਾਲੀ ਭਰੋਸੇਯੋਗ ਵਿਵਹਾਰ ਚਾਹੁੰਦੇ ਹੋ। ਇਹ modern stacks (ਉਦਾਹਰਨ ਵਜੋਂ React + Go + PostgreSQL) 'ਤੇ ਤੇਜ਼ੀ ਨਾਲ ਬਣੇ ਐਪਸ ਲਈ ਕੁਦਰਤੀ ਚੋਣ ਹੈ।\n\nਇਹ ਉਹਨਾਂ ਹਾਲਤਾਂ ਲਈ ਠੀਕ ਨਹੀਂ ਜਦੋਂ ਤੁਹਾਨੂੰ ਬਹੁਤ ਉੱਚ throughput, ਲੰਬੇ-ਚਲਣ ਵਾਲੇ jobs ਜੋ ਪ੍ਰਗਤੀ stream ਕਰਨੇ ਹੋਣ, ਕਈ job ਕਿਸਮਾਂ ਵਿੱਚ ਕੜੀ ordering ਚਾਹੀਦੀ ਹੋਵੇ, ਜਾਂ ਭਾਰੀ fan-out (ਹਰ ਮਿੰਟ ਹਜ਼ਾਰਾਂ sub-tasks) ਹੋਵੇ। ਉਹਨਾਂ ਹਾਲਤਾਂ ਵਿੱਚ ਇੱਕ ਅਸਲੀ queue ਅਤੇ ਡੈਡੀਕੇਟਿਡ workers ਆਮ ਤੌਰ 'ਤੇ ਆਪਣਾ ਫਾਇਦਾ ਦਿਖਾਉਂਦੇ ਹਨ।\n\n## ਸਧਾਰਨ ਭਾਸ਼ਾ ਵਿੱਚ ਮੁੱਖ ਵਿਚਾਰ\n\nਕਰੋਨ + ਡੇਟਾਬੇਸ ਪੈਟਰਨ scheduled background work chalaunda ਹੈ ਬਿਨਾਂ ਪੂਰੇ queue ਸਿਸਟਮ ਦੇ। ਤੁਸੀਂ ਹੁਣ ਵੀ cron (ਜਾਂ ਕੋਈ ਵੀ scheduler) ਵਰਤਦੇ ਹੋ, ਪਰ cron ਇਹ ਨਹੀਂ ਫੈਸਲਾ ਕਰਦਾ ਕਿ ਕੀ ਚਲਾਉਣਾ ਹੈ। ਇਹ ਸਿਰਫ਼ worker ਨੂੰ ਬਾਰ-ਬਾਰ ਜਗਾਉਂਦਾ ਹੈ (ਜ਼ਿਆਦਾਤਰ ਇੱਕ ਮਿੰਟ ਵਿੱਚ ਇੱਕ ਵਾਰੀ)। ਡੇਟਾਬੇਸ ਫੈਸਲਾ ਕਰਦਾ ਹੈ ਕਿ ਕਿਹੜਾ ਕੰਮ ਦੇਣ ਯੋਗ ਹੈ ਅਤੇ ਇਹ ਯਕੀਨੀ ਬਣਾਉਂਦਾ ਹੈ ਕਿ ਹਰ job ਨੂੰ ਕੇਵਲ ਇੱਕ worker ਹੀ ਲੈਂਦਾ ਹੈ।\n\nਇਸਨੂੰ ਇੱਕ ਸਾਂਝਾ ਚੈੱਕਲਿਸਟ ਵਾਲੀ whiteboard ਵਾਂਗ ਸੋਚੋ। Cron ਉਹ ਵਿਅਕਤੀ ਹੈ ਜੋ ਹਰ ਮਿੰਟ ਕਮਰੇ ਵਿੱਚ ਆਉਂਦਾ ਹੈ ਅਤੇ ਕਹਿੰਦਾ ਹੈ, “ਕਿਸੇ ਨੂੰ ਹੁਣ ਕੁਝ ਕਰਨ ਦੀ ਲੋੜ ਹੈ?” ਡੇਟਾਬੇਸ ਉਹ whiteboard ਹੈ ਜੋ ਦਿਖਾਉਂਦਾ ਹੈ ਕਿ ਕੀ ਦੇਣਾ ਹੈ, ਕੀ ਪਹਿਲਾਂ ਹੀ ਲਿਆ ਗਿਆ ਹੈ, ਅਤੇ ਕੀ ਹੋ ਚੁੱਕਾ ਹੈ।\n\nਹਿੱਸੇ ਸਿੱਧੇ ਹਨ:\n\n- ਇੱਕ ਸਿੰਗਲ scheduler trigger ਬਾਰ-ਬਾਰ ਚਲਦਾ ਹੈ।\n- ਇੱਕ jobs ਟੇਬਲ “ਕੀ” ਅਤੇ “ਕਦੋਂ” (due time) ਰੱਖਦੀ ਹੈ, ਨਾਲ ਹੀ status ਅਤੇ attempt count।\n- ਇੱਕ ਜਾਂ ਉਸ ਤੋਂ ਵੱਧ workers ਟੇਬਲ ਨੂੰ poll ਕਰਦੇ ਹਨ, ਇੱਕ job claim ਕਰਦੇ ਹਨ, ਅਤੇ ਕੰਮ ਕਰਦੇ ਹਨ।\n- claim ਕਰਨਾ ਡੇਟਾਬੇਸ ਲਾਕ ਦੀ ਵਰਤੋਂ ਨਾਲ ਹੁੰਦਾ ਹੈ ਤਾਂ ਕਿ ਦੋ workers ਇੱਕੋ row ਨਾ ਲੈ ਲੈਣ।\n- ਡੇਟਾਬੇਸ ਇਹ ਸਤਰੰਸ਼ ਹੈ ਕਿ ਕੀ ਚਲਿਆ, ਕੀ ਫੇਲ ਹੋਇਆ, ਅਤੇ ਕੀ retry ਕਰਨਾ ਚਾਹੀਦਾ ਹੈ।\n\nਉਦਾਹਰਨ: ਤੁਸੀਂ ਹਰ ਸਵੇਰੇ invoice reminders ਭੇਜਣਾ ਚਾਹੁੰਦੇ ਹੋ, ਹਰ 10 ਮਿੰਟ ਬਾਅਦ cache ਤਾਜ਼ਾ ਕਰਨਾ, ਅਤੇ ਰਾਤ ਨੂੰ ਪੁਰਾਣੀਆਂ sessions ਸਾਫ਼ ਕਰਨਾ। ਤਿੰਨ ਵੱਖ-ਵੱਖ cron ਕਮਾਂਡਾਂ ਦੀ ਥਾਂ (ਜੋ ਹਰ ਇੱਕ ਨਾਲ अपना overlap ਅਤੇ ਫੇਲਯੋਗ ਮੋਡ ਰੱਖਦੀਆਂ ਹਨ), ਤੁਸੀਂ job entries ਇੱਕ ਹੀ ਥਾਂ ਸਟੋਰ ਕਰ ਲੈਂਦੇ ਹੋ। Cron ਇੱਕੋ worker ਪ੍ਰਕਿਰਿਆ ਸ਼ੁਰੂ ਕਰਦਾ ਹੈ। Worker Postgres ਨੂੰ ਪੁੱਛਦਾ ਹੈ, “ਹੁਣ ਕੀ ਦੇਣਾ ਚਾਹੀਦਾ ਹੈ?” ਅਤੇ Postgres worker ਨੂੰ ਸੁਰੱਖਿਅਤ ਤਰੀਕੇ ਨਾਲ ਇੱਕ ਵਾਰੀ ਵਿੱਚ ਇੱਕ job claim ਕਰਨ ਦਿੰਦਾ ਹੈ।\n\nਇਹ تدريجي طور ਤੇ ਸਕੇਲ ਹੁੰਦਾ ਹੈ। ਤੁਸੀਂ ਇੱਕ ਸਰਵਰ ਤੇ ਇੱਕ worker ਨਾਲ ਸ਼ੁਰੂ ਕਰ ਸਕਦੇ ਹੋ। ਬਾਅਦ ਵਿੱਚ, ਤੁਸੀਂ ਕਈ ਸਰਵਰਾਂ 'ਤੇ ਪੰਜ workers ਚਲਾ ਸਕਦੇ ਹੋ। Contract ਇੱਕੋ ਰਿਹਾ: ਟੇਬਲ ਹੀ contract ਹੈ।\n\nਮਨੋਦਸ਼ਾ ਸਧਾਰਨ ਹੈ: cron ਸਿਰਫ਼ ਜਾਗਦਾ ਹੈ। ਡੇਟਾਬੇਸ ਟ੍ਰੈਫਿਕ ਕੋਪ ਹੈ ਜੋ ਫੈਸਲਾ ਕਰਦਾ ਹੈ ਕਿ ਕੀ ਚਲ ਸਕਦਾ ਹੈ, ਕੀ ਹੋਇਆ ਉਸਦਾ ਰਿਕਾਰਡ ਰੱਖਦਾ ਹੈ, ਅਤੇ ਜਦੋਂ ਕੁਝ ਗਲਤ ਹੋਵੇ ਤਾਂ ਸਪਸ਼ਟ ਇਤਿਹਾਸ ਦਿੰਦਾ ਹੈ।\n\n## jobs ਟੇਬਲ ਡਿਜ਼ਾਈਨ ਕਰਨਾ (ਇੱਕ عملي schema)\n\nਇਹ ਪੈਟਰਨ ਸਭ ਤੋਂ ਵਧੀਆ ਤਦੋਂ ਕੰਮ ਕਰਦਾ ਹੈ ਜਦੋਂ ਤੁਹਾਡਾ ਡੇਟਾਬੇਸ ਇਹ ਨਿਰਧਾਰਕ ਸਰੋਤ ਬਣ ਜਾਂਦਾ ਹੈ ਕਿ ਕੀ ਚਲਣਾ ਚਾਹੀਦਾ ਹੈ, ਕਦੋਂ ਚਲਣਾ ਚਾਹੀਦਾ ਹੈ, ਅਤੇ ਆਖ਼ਰੀ ਵਾਰ ਕੀ ਹੋਇਆ। schema ੲੁੱਚੇ ਨਹੀਂ ਹੁੰਦੀ, ਪਰ ਛੋਟੀ-ਛੋਟੀ ਚੀਜ਼ਾਂ (lock ਫੀਲਡ ਅਤੇ ਸਹੀ ਇੰਡੈਕਸ) ਜ਼ਰੂਰੀ ਹਨ ਜਦੋਂ load ਵਧਦਾ ਹੈ।\n\n### ਇੱਕ ਟੇਬਲ ਜਾਂ ਦੋ?\n\nਦੋ ਆਮ ਪਹੁੰਚਾਂ:\n\n- **ਇਕ combined ਟੇਬਲ** ਜਦੋਂ ਤੁਸੀਂ ਹਰ job ਦੀ ਆਖ਼ਰੀ ਸਥਿਤੀ 'ਤੇ ਹੀ ਧਿਆਨ ਦਿੰਦੇ ਹੋ (ਸੰਪੂਰਨ, ਘੱਟ joins)।\n- **ਦੋ ਟੇਬਲ** ਜਦੋਂ ਤੁਸੀਂ “ਇਹ job ਕੀ ਹੈ” ਅਤੇ “ਇਸ ਵਾਰੀ ਇੱਕ-ਇੱਕ ਚਲਣ / ਕੋਸ਼ਿਸ਼” ਨੂੰ ਵੱਖਰਾ ਰੱਖਣਾ ਚਾਹੁੰਦੇ ਹੋ (ਵਧੀਆ ਇਤਿਹਾਸ, ਡੀਬੱਗ ਕਰਨ ਵਿੱਚ ਆਸਾਨ)।\n\nਜੇ ਤੁਸੀਂ ਅਕਸਰ ਫੇਲਿਆਵਾਂ ਡੀਬੱਗ ਕਰਨਾ ਚਾਹੁੰਦੇ ਹੋ ਤਾਂ ਇਤਿਹਾਸ ਰੱਖੋ। ਜੇ ਤੁਸੀਂ ਸਭ ਤੋਂ ਛੋਟੀ ਸੰਰਚਨਾ ਚਾਹੁੰਦੇ ਹੋ ਤਾਂ ਇੱਕ ਟੇਬਲ ਨਾਲ ਸ਼ੁਰੂ ਕਰੋ ਅਤੇ ਬਾਅਦ ਵਿੱਚ ਇਤਿਹਾਸ ਜੋੜੋ।\n\n### ਇੱਕ عملي schema (ਦੋ-ਟੇਬਲ ਵਰਜ਼ਨ)\n\nਹੇਠਾਂ PostgreSQL-ਮੈਤਾਬੋਲਿਕ ਲੇਆਊਟ ਹੈ। ਜੇ ਤੁਸੀਂ Go ਨਾਲ PostgreSQL ਬਣਾ ਰਹੇ ਹੋ, ਤਾਂ ਇਹ ਕਾਲਮ structs ਨਾਲ ਅਸਾਨੀ ਨਾਲ ਮੈਪ ਹੋ ਜਾਂਦੇ ਹਨ।\n\n```sql\n-- What should exist (the definition)\ncreate table job_definitions (\n id bigserial primary key,\n job_type text not null,\n payload jsonb not null default '{}'::jsonb,\n schedule text, -- optional: cron-like text if you store it\n max_attempts int not null default 5,\n created_at timestamptz not null default now(),\n updated_at timestamptz not null default now()\n);\n\n-- What should run (each run / attempt group)\ncreate table job_runs (\n id bigserial primary key,\n definition_id bigint references job_definitions(id),\n job_type text not null,\n payload jsonb not null default '{}'::jsonb,\n run_at timestamptz not null,\n status text not null, -- queued | running | succeeded | failed | dead\n attempts int not null default 0,\n max_attempts int not null default 5,\n\n locked_by text,\n locked_until timestamptz,\n\n last_error text,\n created_at timestamptz not null default now(),\n updated_at timestamptz not null default now()\n);\n```\n\nਕੁਝ ਵਿਸ਼ੇਸ਼ ਤੱਥ ਜੋ ਬਾਅਦ ਵਿੱਚ ਦਰਦ ਬਚਾਉਂਦੇ ਹਨ:\n\n- **job_type** ਨੂੰ ਇੱਕ ਛੋਟਾ ਸਤਰ ਰੱਖੋ ਜਿਸ 'ਤੇ ਤੁਸੀਂ ਰਾਊਟ ਕਰ ਸਕੋ (ਜਿਵੇਂ
).\n- **payload** ਨੂੰ
ਵਜੋਂ ਸਟੋਰ ਕਰੋ ਤਾਂ ਜੋ ਤੁਸੀਂ ਬਿਨਾਂ ਮਾਈਗ੍ਰੇਸ਼ਨ ਦੇ ਇਸਨੂੰ ਬਦਲ ਸਕੋ।\n- **run_at** ਤੁਹਾਡਾ "ਅਗਲੀ ਨਿਰਧਾਰਤ ਵਾਰੀ" ਹੈ। Cron (ਜਾਂ scheduler ਸਕ੍ਰਿਪਟ) ਇਹ ਸੈੱਟ ਕਰਦਾ ਹੈ, workers ਇਸਨੂੰ ਖਪਤ ਕਰਦੇ ਹਨ।\n- **locked_by** ਅਤੇ **locked_until** workers ਨੂੰ jobs claim ਕਰਨ ਦਿੰਦੀਆਂ ਹਨ ਬਿਨਾਂ ਇਕ-ਦੂਜੇ 'ਤੇ ਚੱਲਣ ਦੇ।\n- **last_error** ਛੋਟੀ ਅਤੇ ਮਨੁੱਖੀ-ਪੜ੍ਹਨਯੋਗ ਹੋਣੀ ਚਾਹੀਦੀ ਹੈ। ਜੇ ਤੁਹਾਨੂੰ stack traces ਚਾਹੀਦੇ ਹਨ ਤਾਂ ਉਹ ਹੋਰ ਥਾਂ ਰੱਖੋ।\n\n### ਉਹ ਇੰਡੈਕਸ ਜੋ ਤੁਸੀਂ ਚਾਹੁੰਦੇ ਹੋ\n\nਬਿਨਾਂ ਇੰਡੈਕਸਾਂ ਦੇ, workers ਜ਼ਿਆਦਾ scan ਕਰਨਗੇ। ਸ਼ੁਰੂਆਤ ਲਈ:\n\n- ਇੱਕ ਇੰਡੈਕਸ ਜੋ due work ਤੇਜ਼ੀ ਨਾਲ ਲੱਭੇ:
\n- ਇੱਕ ਇੰਡੈਕਸ ਜੋ expired locks ਨੂੰ ਪਹਿਚਾਣਨ ਵਿੱਚ ਮਦਦ ਕਰੇ:
\n- ਵਿਕਲਪਿਕ: active work ਲਈ partial index (ਉਦਾਹਰਨ ਲਈ, status
ਅਤੇ
)\n\nਇਹ "ਅਗਲਾ runnable job ਲੱਭੋ" ਕੁਏਰੀ ਨੂੰ ਤੇਜ਼ ਰੱਖਦੇ ਹਨ ਭਾਵੇਂ ਟੇਬਲ ਵੱਡੀ ਹੋ ਜਾਏ।\n\n## ਸੁਰੱਖਿਅਤ ਤਰੀਕੇ ਨਾਲ jobs claim ਅਤੇ locking\n\nਲਕਸ਼ਯ ਸਧਾਰਨ ਹੈ: ਬਹੁਤWorkers ਚਲ ਸਕਦੇ ਹਨ, ਪਰ ਸਿਰਫ਼ ਇੱਕ ਨੂੰ ਹੀ ਇੱਕ ਖਾਸ job ਲੈਣਾ ਚਾਹੀਦਾ ਹੈ। ਜੇ ਦੋ workers ਇੱਕੋ row ਨੂੰ process ਕਰ ਲੈਂਦੇ ਹਨ, ਤਾਂ ਤੁਸੀਂ double emails, double charges, ਜਾਂ ਗੰਦੇ ਡਾਟਾ ਪਾਉਂਗੇ।\n\nਇੱਕ ਸੁਰੱਖਿਅਤ ਤਰੀਕਾ job claim ਨੂੰ ਇੱਕ “lease” ਵਾਂਗ ਵਰਤਣਾ ਹੈ। Worker job ਨੂੰ ਇੱਕ ਛੋਟੇ ਸਮੇਂ ਲਈ locked ਕਰਦਾ ਹੈ। ਜੇ worker crash ਹੋ ਜਾਂਦਾ ਹੈ, ਤਾਂ lease expire ਹੋ ਜਾਂਦੀ ਹੈ ਅਤੇ ਦੂਜਾ worker ਉਹਨੂੰ ਲੈ ਸਕਦਾ ਹੈ। ਇਹੀ ਕਾਰਨ
ਹੈ।\n\n### crashes ਸਦਾ ਕੰਮ ਨੂੰ ਰੋਕਣ ਨਾ ਕਰਨ ਲਈ lease ਦੀ ਵਰਤੋਂ ਕਰੋ\n\nਬਿਨਾਂ lease ਦੇ, ਇੱਕ worker job ਨੂੰ lock ਕਰਕੇ ਕਦੇ unlock ਨਹੀਂ ਕਰ ਸਕਦਾ (process kill ਹੋਈ, ਸਰਵਰ reboot, deploy ਗਲਤ ਹੋ ਗਿਆ)।
ਨਾਲ job ਸਮੇਂ ਬਾਅਦ ਦੁਬਾਰਾ ਉਪਲਬਧ ਹੋ ਜਾਂਦੀ ਹੈ।\n\nਆਮ ਨਿਯਮ: ਇੱਕ job ਨੂੰ claim ਕੀਤਾ ਜਾ ਸਕਦਾ ਹੈ ਜਦੋਂ
ਹੋਵੇ ਜਾਂ
ਹੋਵੇ।\n\n### jobs ਨੂੰ atomic update ਨਾਲ claim ਕਰੋ\n\nਮੁੱਖ ਵਿਸ਼ੇਸ਼ਤਾ ਇਹ ਹੈ ਕਿ job claim ਇੱਕ single statement (ਜਾਂ ਇੱਕ transaction) ਵਿੱਚ ਹੋਵੇ। ਤੁਸੀਂ ਚਾਹੁੰਦੇ ਹੋ ਕਿ ਡੇਟਾਬੇਸ ਰੈਫਰੀ ਹੋਵੇ।\n\nਇਥੇ ਇੱਕ ਆਮ PostgreSQL ਪੈਟਰਨ ਹੈ: ਇੱਕ due job ਚੁਣੋ, ਇਸਨੂੰ lock ਕਰੋ, ਅਤੇ worker ਨੂੰ ਵਾਪਸ ਕਰੋ। (ਇਹ ਉਦਾਹਰਨ ਇੱਕ single
ਟੇਬਲ ਵਰਤਦੀ ਹੈ; ਉਹੀ ਵਿਚਾਰ
ਤੋਂ claim ਕਰਨ ’ਤੇ ਲਾਗੂ ਹੁੰਦਾ ਹੈ.)\n\n```sql\nWITH next_job AS (\n SELECT id\n FROM jobs\n WHERE status = 'queued'\n AND run_at \u003c= now()\n AND (locked_until IS NULL OR locked_until \u003c= now())\n ORDER BY run_at ASC\n LIMIT 1\n FOR UPDATE SKIP LOCKED\n)\nUPDATE jobs j\nSET status = 'running',\n locked_until = now() + interval '2 minutes',\n locked_by = $1,\n attempts = attempts + 1,\n updated_at = now()\nFROM next_job\nWHERE j.id = next_job.id\nRETURNING j.*;\n```\n\nਕਿਉਂ ਇਹ ਕੰਮ ਕਰਦਾ ਹੈ:\n\n-
ਬਹੁਤWorkers ਨੂੰ ਮੁਕਾਬਲਾ ਕਰਨ ਦਿੰਦਾ ਹੈ ਬਿਨਾਂ ਇਕ-ਦੂਜੇ ਨੂੰ ਬਲਾਕ ਕੀਤੇ।\n- lease claim ਸਮੇਂ ਸੈੱਟ ਹੁੰਦੀ ਹੈ, ਤਾਂਕੇ ਹੋਰ workers ਇਸ ਨੂੰ expiry ਤੱਕ ਨਜ਼ਰਅੰਦਾਜ਼ ਕਰਦੇ ਹਨ।\n-
ਉਸ ਪਰਤ ਨੂੰ worker ਨੂੰ ਦੇ ਦਿੰਦਾ ਹੈ ਜਿਸ ਨੇ race ਜਿੱਤੀ।\n\n### lease ਕਿੰਨੀ ਲੰਬੀ ਹੋਣੀ ਚਾਹੀਦੀ ਹੈ, ਅਤੇ ਕਿਵੇਂ renew ਕਰਨੀ ਹੈ?\n\nlease ਨੂੰ ਤੁਹਾਡੇ ਆਮ run ਤੋਂ ਲੰਮਾ ਰੱਖੋ, ਪਰ ਇਸ ਤਰ੍ਹਾਂ ਛੋਟਾ ਰੱਖੋ ਕਿ ਇੱਕ crash ਜਲਦੀ recover ਹੋ ਜਾਵੇ। ਜੇ ਅਧਿਕਤਰ jobs 10 ਸਕਿੰਟ ਵਿੱਚ ਖਤਮ ਹੁੰਦੇ ਹਨ, ਤਾਂ 2 ਮਿੰਟ ਦਾ lease ਕਾਫ਼ੀ ਹੈ।\n\nਲੰਬੇ ਕੰਮਾਂ ਲਈ, ਕੰਮ ਕਰਦਿਆਂ lease renew (heartbeat) ਕਰੋ। ਆਮ ਤੌਰ 'ਤੇ: ਹਰ 30 ਸਕਿੰਟ ਮਧੀਨ
ਵਧਾਓ ਜੇ ਤੁਸੀਂ ਅਜੇ ਵੀ job ਦੇ ਮਾਲਕ ਹੋ।\n\n- Lease ਦੀ ਲੰਬਾਈ: ਤੁਹਾਡੇ ਆਮ job ਸਮੇਂ ਦਾ 5x ਤੋਂ 20x\n- Heartbeat interval: lease ਦਾ 1/4 ਤੋਂ 1/2\n- Renewal update ਵਿੱਚ
ਸ਼ਾਮਲ ਕਰੋ\n\nਇਹ ਆਖਰੀ ਸ਼ਰਤ ਮਹੱਤਵਪੂਰਣ ਹੈ। ਇਹ ਰੋਕਦੀ ਹੈ ਕਿ ਕੋਈ worker ਕਿਸੇ job ਨੂੰ extend ਕਰੇ ਜਿਸ ਦਾ ਉਹ ਹੁਣ ਮਾਲਕ ਨਹੀਂ।\n\n## retries ਅਤੇ backoff ਜੋ ਪੈਟਰਨ ਅਨੁਸਾਰ ਵਰਤਦੇ ਹਨ\n\nRetries ਉਹ ਜਗ੍ਹਾ ਹੈ ਜਿੱਥੇ ਇਹ ਪੈਟਰਨ ਸ਼ਾਂਤ ਮਹਿਸੂਸ ਕਰਦੈ ਜਾਂ ਸ਼ੋਰਮਚਾਉਣ ਵਾਲਾ ਬਣ ਜਾਂਦਾ ਹੈ। ਲਕਸ਼ਯ ਸਧਾਰਨ ਹੈ: ਜਦੋਂ ਕੋਈ job fail ਕਰਦਾ ਹੈ, ਤਾਂ ਦੁਬਾਰਾ ਇਕ ਸਮਝਦਾਰ ਤਰੀਕੇ ਨਾਲ ਬਾਅਦ ਵਿੱਚ ਕੋਸ਼ਿਸ਼ ਕਰੋ, ਜਿਸਨੂੰ ਤੁਸੀਂ ਵਿਆਖਿਆ ਕਰ ਸਕੋ, ਮਾਪ ਸਕੋ ਅਤੇ ਰੋਕ ਸਕੋ।\n\nਸਭ ਤੋਂ ਪਹਿਲਾਂ job state ਨਿਰਧਾਰਤ ਅਤੇ finite ਬਣਾਓ:
,
,
,
,
। ਅਮਲੀ ਤੌਰ 'ਤੇ, ਜ਼ਿਆਦਾਤਰ ਟੀਮਾਂ
ਨੂੰ “ਫੇਲ ਹੋਇਆ ਪਰ ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕੀਤਾ ਜਾਵੇਗਾ” ਅਤੇ
ਨੂੰ “ਫੇਲ ਹੋਇਆ ਅਤੇ ਅਸੀਂ ਹਾਰ ਮੰਨ ਲਈ” ਵਜੋਂ ਵਰਤਦੀਆਂ ਹਨ। ਇਹ ਇਕਫਰਕ ਅਨੰਤ ਲੂਪ ਰੋਕਦਾ ਹੈ।\n\nAttempt counting ਦੂਜਾ ਗਾਰਡਰੇਲ ਹੈ।
(ਕਿੰਨੀ ਵਾਰੀ ਕੋਸ਼ਿਸ਼ ਕੀਤੀ) ਅਤੇ
(ਕਿੰਨੀ ਵਾਰੀ ਆਗਿਆ ਹੈ) ਸਟੋਰ ਕਰੋ। ਜਦੋਂ worker ਇੱਕ error ਫੜਦਾ ਹੈ, ਇਹਨੂੰ ਕਰਨਾ ਚਾਹੀਦਾ ਹੈ:\n\n-
ਵਧਾਓ\n- ਜੇ
ਤਾਂ state ਨੂੰ
ਸੈੱਟ ਕਰੋ, ਨਹੀਂ ਤਾਂ
\n- ਅਗਲੀ ਕੋਸ਼ਿਸ਼ ਲਈ
ਗਣਨਾ ਕਰੋ (ਸਰਫ਼
ਲਈ)\n\nBackoff ਸਿਰਫ਼ ਨਿਯਮ ਹੈ ਜੋ ਅਗਲਾ
ਨਿਰਧਾਰਤ ਕਰਦਾ ਹੈ। ਇੱਕ ਚੁਣੋ, ਦਸਤਾਵੇਜ਼ ਬਣਾਓ, ਅਤੇ ਸਥਿਰ ਰੱਖੋ:\n\n- Fixed delay: ਹਮੇਸ਼ਾ 1 ਮਿੰਟ ਦੂਰ\n- Exponential: 1m, 2m, 4m, 8m\n- Exponential with a cap: exponential ਪਰ ਕਦੇ ਵੀ 30m ਤੋਂ ਜ਼ਿਆਦਾ ਨਹੀਂ\n- Jitter ਜੋੜੋ: ਥੋੜ੍ਹਾ randomize ਕਰੋ ਤਾਂ ਜੋ ਸਾਰੇ jobs ਇੱਕੋ ਸਕਿੰਟ 'ਤੇ retry ਨਾ ਕਰਨ\n\nJitter ਉਸ ਵੇਲੇ ਮਹੱਤਵਪੂਰਣ ਹੁੰਦਾ ਹੈ ਜਦੋਂ ਕੋਈ dependency ਡਾਊਨ ਹੋ ਕੇ ਵਾਪਸ ਆਉਂਦੀ ਹੈ। ਬਿਨਾਂ ਇਸ ਦੇ, ਸੈਂਕੜੇ jobs ਇਕੱਠੇ retry ਕਰਕੇ ਫੇਰ ਫੇਲ ਹੋ ਸਕਦੇ ਹਨ।\n\nਫੇਲਯੋਗੀਆਂ ਨੂੰ ਡੀਬੱਗ ਕਰਨ ਲਈ ਕਾਫ਼ੀ error detail ਸਟੋਰ ਕਰੋ। ਤੁਹਾਨੂੰ ਪੂਰਾ logging ਸਿਸਟਮ ਦੀ ਲੋੜ ਨਹੀਂ, ਪਰ ਬੁਨਿਆਦੀ ਚੀਜ਼ਾਂ ਹਨ:\n\n-
(ਛੋਟੀ ਸੁਨੇਹਾ, admin ਸਕ੍ਰੀਨ 'ਤੇ ਦਿਖਾਉਣ ਲਈ ਸੁਰੱਖਿਅਤ)\n-
ਜਾਂ
(ਗਰੂਪਿੰਗ ਵਿੱਚ ਮਦਦ)\n-
ਅਤੇ
\n- ਵਿਕਲਪਿਕ
(ਜੇ ਤੁਸੀਂ ਆਕਾਰ ਸਮਭਾਲ ਸਕਦੇ ਹੋ)\n\nਇੱਕ ਠੋਸ ਨਿਯਮ ਜੋ ਵਧੀਆ ਕੰਮ ਕਰਦਾ ਹੈ: jobs ਨੂੰ 10 ਕੋਸ਼ਿਸ਼ਾਂ ਤੋਂ ਬਾਅਦ
ਮਾਰਕ ਕਰੋ, ਅਤੇ exponential backoff ਨਾਲ jitter ਰੱਖੋ। ਇਹ ਟਰਾਂਜ਼ੀਐਂਟ ਫੇਲਯੋਗੀਆਂ ਨੂੰretry ਕਰਨ ਦਿੰਦਾ ਹੈ, ਪਰ ਟੁੱਟੇ ਹੋਏ jobs ਨੂੰ ਲਗਾਤਾਰ CPU ਖਰਚਣ ਤੋਂ ਰੋਕਦਾ ਹੈ।\n\n## Idempotency: duplicates ਨੂੰ ਰੋਕਣਾ ਜਦੋਂ job ਦੁਬਾਰਾ ਚਲਾਇਆ ਜਾਵੇ\n\nIdempotency ਦਾ ਮਤਲਬ ਹੈ ਕਿ ਤੁਹਾਡਾ job ਦੋ ਵਾਰੀ ਚਲਾਇਆ ਜਾਵੇ ਅਤੇ ਫਿਰ ਵੀ ਉਹੀ ਅੰਤਿਮ ਨਤੀਜਾ ਦੇਵੇ। ਇਸ ਪੈਟਰਨ ਵਿੱਚ ਇਹ ਮਹੱਤਵਪੂਰਣ ਹੈ ਕਿਉਂਕਿ ਇੱਕੋ row ਮੁੜ ਚੁਣਿਆ ਜਾ ਸਕਦਾ ਹੈ crash, timeout ਜਾਂ retry ਕਾਰਨ। ਜੇ ਤੁਹਾਡਾ job "invoice email ਭੇਜੋ" ਹੈ, ਤਾਂ ਇਹ ਦੋ ਵਾਰੀ ਚਲਾਉਣਾ ਨਿਰਪੱਖ ਨਹੀਂ ਹੈ।\n\nਅਮਲੀ ਸੋਚ ਇਹ ਹੈ: ਹਰ job ਨੂੰ (1) ਕੰਮ ਕਰਨਾ ਅਤੇ (2) ਪ੍ਰਭਾਵ ਲਗਾਉਣਾ ਵਿੱਚ ਵੰਡੋ। ਪ੍ਰਭਾਵ ਨੂੰ ਇੱਕ ਵਾਰੀ ਹੋਣਾ ਚਾਹੀਦਾ ਹੈ, ਚਾਹੇ ਕੰਮ ਕਈ ਵਾਰ ਕੋਸ਼ਿਸ਼ ਕੀਤੀ ਜਾਵੇ।\n\n### ਵਪਾਰਕ ਘਟਨਾ ਨਾਲ ਜੁੜਿਆ idempotency key ਵਰਤੋ\n\nIdempotency key ਉਸ ਚੀਜ਼ ਤੋਂ ਆਉਣਾ ਚਾਹੀਦਾ ਹੈ ਜੋ job ਦਰਸਾਉਂਦਾ ਹੈ, worker ਦੀ ਕੋਸ਼ਿਸ਼ ਤੋਂ ਨਹੀਂ। ਚੰਗੇ ਕੀ stable ਅਤੇ ਆਸਾਨ ਹੋਵਣਗੇ, ਜਿਵੇਂ
,
, ਜਾਂ
। ਜੇ ਦੋ ਕੋਸ਼ਿਸ਼ਾਂ ਇੱਕੋ ਹਕੀਕਤੀ ਘਟਨਾ ਨਾਲ ਸਬੰਧਿਤ ਹਨ, ਉਹ ਇੱਕੋ key ਸਾਂਝੀਆਂ ਕਰਣ।\n\nਉਦਾਹਰਨ: “2026-01-14 ਲਈ daily sales report ਬਣਾਓ” ਲਈ
ਵਰਤ ਸਕਦੇ ਹੋ। “Invoice 812 charge ਕਰੋ” ਲਈ
ਵਰਤੋ।\n\n### ਡੇਟਾਬੇਸ constraints ਨਾਲ “ਕੇਵਲ ਇੱਕ ਵਾਰੀ” ਲਾਗੂ ਕਰੋ\n\nਸਭ ਤੋਂ ਸਧਾਰਣ ਗਾਰਡਰੇਲ PostgreSQL ਨੂੰ duplicates reject ਕਰਨ ਦੇਣੀ ਹੈ। idempotency key ਨੂੰ ਕਿਸੇ ਸਥਾਨ 'ਤੇ ਸਟੋਰ ਕਰੋ ਜੋ ਇੰਡੈਕਸ ਕੀਤਾ ਜਾ ਸਕਦਾ ਹੈ, ਫਿਰ unique constraint ਜੋੜੋ।\n\n```sql\n-- Example: ensure one logical job/effect per business key\nALTER TABLE jobs\nADD COLUMN idempotency_key text;\n\nCREATE UNIQUE INDEX jobs_idempotency_key_uniq\nON jobs (idempotency_key)\nWHERE idempotency_key IS NOT NULL;\n```\n\nਇਸ ਨਾਲ ਇੱਕੋ key ਵਾਲੀਆਂ ਦੋ rows ਇੱਕੋ ਸਮੇਂ ਮੌਜੂਦ ਨਹੀਂ ਹੋ ਸਕਦੀਆਂ। ਜੇ ਤੁਹਾਡੀ ਡਿਜ਼ਾਈਨ ਵਿੱਚ ਕਈ rows ਦੀ ਆਗਿਆ ਹੈ (ਇਤਿਹਾਸ ਲਈ), ਤਾਂ uniqueness ਨੂੰ effects ਟੇਬਲ ਤੇ ਰੱਖੋ, ਜਿਵੇਂ
ਜਾਂ
.\n\nਸਧਾਰਨ side effects ਜੋ ਰੋਕੇ ਜਾਣੇ ਚਾਹੀਦੇ ਹਨ:\n\n- Emails:
row with unique key ਬਣਾਓ ਭੇਜਣ ਤੋਂ ਪਹਿਲਾਂ, ਜਾਂ ਭੇਜਣ ਤੋਂ ਬਾਅਦ provider message id ਰਿਕਾਰਡ ਕਰੋ।\n- Webhooks:
ਸਟੋਰ ਕਰੋ ਅਤੇ ਜੇ ਮੌਜੂਦ ਹੋਵੇ ਤਾਂ skip ਕਰੋ।\n- Payments: ਹਮੇਸ਼ਾ payment provider ਦੀ idempotency ਫੀਚਰ ਨਾਲ ਨਾਲ ਆਪਣਾ unique database key ਵਰਤੋ।\n- File writes: temp ਨਾਂ 'ਤੇ ਲਿਖੋ ਅਤੇ ਫਿਰ rename ਕਰੋ, ਜਾਂ
ਨਾਲ keyed
record ਰੱਖੋ।\n\nਜੇ ਤੁਸੀਂ Postgres-backed stack (ਉਦਾਹਰਨ: Go + PostgreSQL) 'ਤੇ ਨਿਰਮਾਣ ਕਰ ਰਹੇ ਹੋ, ਤਾਂ ਇਹ uniqueness checks ਤੇਜ਼ ਅਤੇ ਡਾਟਾ ਦੇ ਨੇੜੇ ਰਹਿਣਗੇ। ਮੁੱਖ ਵਿਚਾਰ ਸਧਾਰਨ ਹੈ: retries ਸਧਾਰਨ ਹਨ, duplicates optional ਹਨ।\n\n## ਕਦਮ-ਦਰ-कਦਮ: ਇੱਕ ਘੱਟੋ-ਘੱਟ worker ਅਤੇ scheduler ਬਣਾਓ\n\nਇੱਕ ਰੁਟਿਨ runtime ਲੋ ਅਤੇ ਉਸ 'ਤੇ ਟਿਕੇ ਰਹੋ। ਕਰੋਨ + ਡੇਟਾਬੇਸ ਪੈਟਰਨ ਦਾ ਮਕਸਦ ਘੱਟ moving parts ਹੈ, ਸੋ ਇੱਕ ਛੋਟਾ Go, Node, ਜਾਂ Python ਪ੍ਰੋਸੈਸ ਜੋ PostgreSQL ਨਾਲ ਗੱਲ ਕਰਦਾ ਹੈ ਆਮ ਤੌਰ 'ਤੇ ਕਾਫ਼ੀ ਹੁੰਦਾ ਹੈ।\n\n### ਪੰਜ ਛੋਟੇ ਕਦਮਾਂ ਵਿੱਚ ਬਣਾਓ\n\n1) **ਟੇਬਲਾਂ ਅਤੇ ਇੰਡੈਕਸ ਬਣਾਓ।** ਇੱਕ
ਟੇਬਲ (ਅਤੇ ਬਾਅਦ ਲਈ ਕੋਈ_LOOKUP ਟੇਬਲ) ਜੋੜੋ, ਫਿਰ
ਤੇ ਇੰਡੈਕਸ ਕਰੋ, ਅਤੇ ਇੱਕ ਇੰਡੈਕਸ ਜੋ worker ਨੂੰ ਉਪਲਬਧ jobs ਤੇਜ਼ੀ ਨਾਲ ਲੱਭਣ ਵਿੱਚ ਮਦਦ ਕਰੇ (ਉਦਾਹਰਨ ਲਈ
).\n\n2) **ਛੋਟਾ enqueue ਫੰਕਸ਼ਨ ਲਿਖੋ।** ਤੁਹਾਡੀ ਐਪ ਇੱਕ row insert ਕਰੇ ਜਿਸ 'ਚ
ਨੂੰ “now” ਜਾਂ ਭਵਿੱਖ ਦਾ ਸਮਾਂ ਸੈੱਟ ਕੀਤਾ ਗਿਆ ਹੋਵੇ।payload ਛੋਟਾ ਅਤੇ ਪੇਸ਼ਾਨਾ ਰੱਖੋ (IDs ਅਤੇ job type, ਵੱਡੇ blobs ਨਹੀਂ)।\n\n```sql\nINSERT INTO jobs (type, payload, status, run_at, attempts, max_attempts)\nVALUES ($1, $2::jsonb, 'queued', $3, 0, 10);\n```\n\n3) **claim loop ਲਾਗੂ ਕਰੋ।** ਇਸਨੂੰ transaction ਵਿੱਚ ਚਲਾਓ। ਕੁਝ due jobs select ਕਰੋ, ਉਹਨਾਂ ਨੂੰ lock ਕਰੋ ਤਾਂਕਿ ਹੋਰ workers ਉਹਨਾਂ ਨੂੰ skip ਕਰਨ, ਅਤੇ ਇੱਕੋ transaction ਵਿੱਚ ਉਹਨਾਂ ਨੂੰ
ਸੈੱਟ ਕਰੋ।\n\n```sql\nWITH picked AS (\n SELECT id\n FROM jobs\n WHERE status = 'queued' AND run_at \u003c= now()\n ORDER BY run_at\n FOR UPDATE SKIP LOCKED\n LIMIT 10\n)\nUPDATE jobs\nSET status = 'running', started_at = now()\nWHERE id IN (SELECT id FROM picked)\nRETURNING *;\n```\n\n4) **Process ਅਤੇ finalize ਕਰੋ।** ਹਰ claimed job ਲਈ, ਕੰਮ ਕਰੋ, ਫਿਰ
ਵਿੱਚ update ਕਰੋ
ਨਾਲ। ਜੇ ਫੇਲ ਹੁੰਦਾ ਹੈ, ਤਾਂ error message ਰਿਕਾਰਡ ਕਰੋ ਅਤੇ ਉਸ ਨੂੰ
ਵਿੱਚ ਨਵਾਂ
(backoff) ਦੇ ਕੇ ਵਾਪਸ ਰੱਖੋ। finalization updates ਛੋਟੇ ਰੱਖੋ ਅਤੇ ਉਹਨਾਂ ਨੂੰ ਸਦਾ ਚਲਾਉ, ਭਾਵੇਂ ਤੁਹਾਡੀ ਪ੍ਰਕਿਰਿਆ shutting down ਹੋ ਰਹੀ ਹੋਵੇ।\n\n5) **retry ਨਿਯਮ ਜੋ ਤੁਸੀਂ ਸਮਝਾ ਸਕੋ ਜੋੜੋ।** ਇੱਕ ਸਧਾਰਨ ਫੌਰਮੂਲਾ ਵਰਤੋ ਜਿਵੇਂ
, ਅਤੇ
ਤੋਂ ਬਾਅਦ
ਕਰ ਦਿਓ।\n\n### ਮੁੱਢਲੈ ਵਿਜ਼ੀਬਿਲਿਟੀ ਜੋੜੋ\n\nਦਿਨ-ਇੱਕ ਦਿਨ ਦਾ ਡੈਸ਼ਬੋਰਡ ਨਹੀਂ ਚਾਹੀਦਾ, ਪਰ ਤੁਹਾਨੂੰ ਸਮੱਸਿਆਵਾਂ ਨੋਟਿਸ ਕਰਨ ਲਈ ਕਾਫ਼ੀ ਚੀਜ਼ਾਂ ਚਾਹੀਦੀਆਂ ਹਨ।\n\n- ਹਰ job ਲਈ ਇਕ ਲਾਈਨ ਲੌਗ ਕਰੋ: claimed, succeeded, failed, retried, dead।\n- “dead jobs” ਅਤੇ “purane running jobs” ਲਈ ਇੱਕ ਸਧਾਰਨ admin query ਜਾਂ view ਬਣਾਓ।\n- counts 'ਤੇ alert ਜੋੜੋ (ਉਦਾਹਰਨ ਲਈ, ਪਿਛਲੇ ਘੰਟੇ ਵਿੱਚ N ਤੋਂ ਵੱਧ dead jobs)।\n\nਜੇ ਤੁਸੀਂ ਪਹਿਲਾਂ ਹੀ Go + PostgreSQL ਸਟੈਕ 'ਤੇ ਹੋ, ਇਹ ਇੱਕ single worker binary + cron ਨਾਲ ਸਾਫ਼ ਮੈਪ ਹੁੰਦਾ ਹੈ।\n\n## ਇੱਕ ਹਕੀਕਤੀ ਉਦਾਹਰਨ ਜੋ ਤੁਸੀਂ ਕਾਪੀ ਕਰ ਸਕਦੇ ਹੋ\n\nਕਲਪਨਾ ਕਰੋ ਇੱਕ ਛੋਟੀ SaaS ਐਪ ਜਿਸ ਨੇ ਦੋ scheduled ਕੰਮ ਹਨ:\n\n- ਇੱਕ ਰਾਤੀ cleanup ਜੋ expired sessions ਅਤੇ ਪੁਰਾਣੀਆਂ temporary files ਹਟਾਉਂਦਾ ਹੈ।\n- ਇੱਕ ਹਫਤਾਵਾਰੀ “ਤੁਹਾਡੀ activity report” ਈਮੇਲ ਜੋ ਹਰ ਸੋਮਵਾਰ ਸਵੇਰੇ ਹਰ ਯੂਜ਼ਰ ਨੂੰ ਭੇਜੀ ਜਾਂਦੀ ਹੈ।\n\nਸਰਲ ਰੱਖੋ: jobs ਨੂੰ ਰੱਖਣ ਲਈ ਇੱਕ PostgreSQL ਟੇਬਲ, ਅਤੇ ਹਰ ਮਿੰਟ ਚਲਣ ਵਾਲਾ ਇੱਕ worker (cron ਦੁਆਰਾ trigger)। Worker due jobs claim ਕਰਦਾ ਹੈ, ਉਹਨਾਂ ਨੂੰ ਚਲਾਉਂਦਾ ਹੈ, ਅਤੇ success ਜਾਂ failure ਰਿਕਾਰਡ ਕਰਦਾ ਹੈ।\n\n### ਕੀ enqueue ਹੁੰਦਾ ਹੈ, ਅਤੇ ਕਦੋਂ\n\nਤੁਸੀਂ jobs ਕਈ ਥਾਵਾਂ ਤੋਂ enqueue ਕਰ ਸਕਦੇ ਹੋ:\n\n- ਹਰ ਰੋਜ਼ 02:00 ਤੇ: ਇੱਕ
job enqueue ਕਰੋ “ਉਸ ਦਿਨ” ਲਈ।\n- ਸਾਈਨਅਪ 'ਤੇ: ਇੱਕ
job ਉਸ ਯੂਜ਼ਰ ਦੇ ਅਗਲੇ ਸੋਮਵਾਰ ਲਈ enqueue ਕਰੋ।\n- ਕਿਸੇ ਘਟਨਾ ਤੋਂ ਬਾਅਦ (ਜਿਵੇਂ “ਯੂਜ਼ਰ ਨੇ Export report ਕਲਿੱਕ ਕੀਤਾ”): ਇੱਕ
job instantaneous ਤੌਰ ਤੇ ਇੱਕ ਨਿਰਧਾਰਤ date range ਲਈ enqueue ਕਰੋ।\n\npayload ਸਿਰਫ਼ ਘੱਟੋ-ਘੱਟ ਜਾਣਕਾਰੀ ਰੱਖੋ ਜੋ worker ਨੂੰ ਚਾਹੀਦੀ ਹੈ। ਇਸਨੂੰ ਛੋਟਾ ਰੱਖੋ ਤਾਂ retry ਆਸਾਨ ਹੋਵੇ।\n\n```json\n{\n "type": "send_weekly_report",\n "payload": {\n "user_id": 12345,\n "date_range": {\n "from": "2026-01-01",\n "to": "2026-01-07"\n }\n }\n}\n```\n\n### idempotency ਕਿਵੇਂ double sending ਰੋਕਦੀ ਹੈ\n\nWorker ਸਭ ਤੋਂ ਖਰਾਬ ਪਲ 'ਤੇ crash ਕਰ ਸਕਦਾ ਹੈ: ਈਮੇਲ ਭੇਜਣ ਤੋਂ ਬਾਅਦ ਪਰ job ਨੂੰ “done” ਨਾਲ ਮਾਰਕ ਕਰਨ ਤੋਂ ਪਹਿਲਾਂ। ਜਦੋਂ ਇਹ restart ਹੁੰਦਾ ਹੈ, ਇਹ ਇਕੋ job ਮੁੜ ਚੁਣ ਸਕਦਾ ਹੈ।\n\nDuplicate-sends ਰੋਕਣ ਲਈ, ਕੰਮ ਨੂੰ ਇੱਕ ਕੁਦਰਤੀ dedupe key ਦਿਓ ਅਤੇ ਉਹ record ਐਸੇ ਥਾਂ ਰੱਖੋ ਜਿੱਥੇ ਡੇਟਾਬੇਸ enforce ਕਰ ਸਕੇ। weekly reports ਲਈ, ਚੰਗਾ key ਹੈ
. ਭੇਜਣ ਤੋਂ ਪਹਿਲਾਂ worker “ਮੈਂ report X ਭੇਜਣ ਵਾਲਾ ਹਾਂ” ਰਿਕਾਰਡ ਕਰਦਾ ਹੈ। ਜੇ ਉਹ record ਪਹਿਲਾਂ ਹੀ ਮੌਜੂਦ ਹੋਵੇ ਤਾਂ skip ਕਰੋ।\n\nਇਹ ਸਿੱਧਾ
ਟੇਬਲ ਨਾਲ ਹੁੰਦਾ ਹੈ ਜਿਸ 'ਤੇ
'ਤੇ unique constraint ਹੋਵੇ, ਜਾਂ job ਖੁਦ
ਰੱਖੇ।\n\n### ਇੱਕ failure ਕਿਵੇਂ ਦਿਸਦਾ ਹੈ (ਅਤੇ ਕਿਵੇਂ recover ਹੁੰਦਾ ਹੈ)\n\nਮਾਨ ਲਓ ਤੁਹਾਡਾ email provider timeout ਦੇ ਦਿੰਦਾ ਹੈ। job fail ਹੋ ਜਾਂਦਾ ਹੈ, ਇਸ ਲਈ worker:\n\n-
ਵਧਾਉਂਦਾ ਹੈ\n- debugging ਲਈ error message ਸੇਵ ਕਰਦਾ ਹੈ\n- backoff ਨਾਲ ਅਗਲੀ ਕੋਸ਼ਿਸ਼ ਸ਼ਡਿਊਲ ਕਰਦਾ ਹੈ (ਉਦਾਹਰਨ: +1 ਮਿੰਟ, +5 ਮਿੰਟ, +30 ਮਿੰਟ, +2 ਘੰਟੇ)\n\nਜੇ ਇਹ ਤੁਹਾਡੇ limit (ਜਿਵੇਂ 10 attempts) ਤੋਂ ਬਾਅਦ ਵੀ fail ਕਰਦਾ ਹੈ, ਤਾਂ ਇਸਨੂੰ
ਮਾਰਕ ਕਰੋ ਅਤੇ retry ਰੋਕ ਦਿਓ। job ਜਾਂ ਤਾਂ ਇਕ ਵਾਰੀ ਸਫਲ ਹੋਵੇਗਾ, ਜਾਂ ਇਹ ਇੱਕ ਸਪਸ਼ਟ ਸ਼ਡਿਊਲ 'ਤੇ retry ਕਰੇਗਾ, ਅਤੇ idempotency retry ਨੂੰ ਸੁਰੱਖਿਅਤ ਬਣਾਏਗਾ।\n\n## ਆਮ ਗਲਤੀਆਂ ਅਤੇ ਫਸਣਾ ਵਾਲੀਆਂ ਜਗ੍ਹਾਂ\n\nਕਰੋਨ + ਡੇਟਾਬੇਸ ਪੈਟਰਨ ਸਧਾਰਨ ਹੈ, ਪਰ ਛੋਟੀਆਂ ਗਲਤੀਆਂ ਇਸਨੂੰ duplicates, stuck work, ਜਾਂ ਅਚਾਨਕ load ਵਿੱਚ ਬਦਲ ਸਕਦੀਆਂ ਹਨ। ਅਕਸਰ ਸਮੱਸਿਆਵਾਂ ਪਹਿਲੇ crash, deploy, ਜਾਂ traffic spike ਤੋਂ ਬਾਅਦ ਆਉਂਦੀਆਂ ਹਨ।\n\n### duplicates ਜਾਂ stuck jobs ਪੈਦਾ ਕਰਨ ਵਾਲੀਆਂ ਗਲਤੀਆਂ\n\nਜ਼ਿਆਦਾਤਰ ਹਕੀਕਤੀ ਘਟਨਾਵਾਂ ਕੁਝ ਜਾਲਾਂ ਤੋਂ ਆਉਂਦੀਆਂ ਹਨ:\n\n- ਉਹੀ job ਵੱਖ-ਵੱਖ cron entries ਤੋਂ ਚਲਾਉਣਾ ਬਿਨਾਂ lease ਦੇ। ਜੇ ਦੋ ਸਰਵਰ ਇੱਕੋ ਮਿੰਟ 'ਤੇ ਟਿਕ ਕਰਦੇ ਹਨ, ਦੋਹਾਂ ਇੱਕੋ ਕੰਮ claim ਕਰ ਸਕਦੇ ਹਨ ਜਦ ਤੱਕ ਤੁਸੀਂ claim step atomic ਨਹੀਂ ਬਣਾਉਂਦੇ ਅਤੇ ਇੱਕੋ ਹੀ transaction ਵਿੱਚ lock (ਜਾਂ lease) ਸੈੱਟ ਨਹੀਂ ਕਰਦੇ।\n-
ਨੂੰ ਛੱਡ ਦਿਤਾ ਗਿਆ। ਜੇ worker claim ਕਰਨ ਤੋਂ ਬਾਅਦ crash ਹੋ ਜਾਂਦਾ ਹੈ, ਤਾਂ row "in progress" ਅਨੰਤਕਾਲ ਲਈ ਰਹਿ ਸਕਦੀ ਹੈ। lease timestamp ਦੂਜੇ worker ਨੂੰ ਬਾਅਦ ਵਿੱਚ safely ਚੁਣਨ ਦਿੰਦੀ ਹੈ।\n- failure 'ਤੇ ਤੁਰੰਤ retry ਕਰਨਾ। ਜਦੋਂ ਕੋਈ API ਡਾਊਨ ਹੋਵੇ, ਤੁਰੰਤ retries spikes ਬਣਾਉਂਦੇ ਹਨ, rate limits ਖਰਚ ਕਰਦੇ ਹਨ, ਅਤੇ ਲਗਾਤਾਰ fail ਹੁੰਦੇ ਰਹਿੰਦੇ ਹਨ। ਹਮੇਸ਼ਾ ਅਗਲੀ ਕੋਸ਼ਿਸ਼ ਨੂੰ ਭਵਿੱਖ ਵਿੱਚ schedule ਕਰੋ।\n- “at least once” ਨੂੰ “exactly once” ਸਮਝਣਾ। ਇੱਕ job ਦੁਬਾਰਾ ਚਲ ਸਕਦੀ ਹੈ (timeouts, worker restarts, network issues)। ਜੇ ਦੋ ਵਾਰੀ ਚਲਣਾ ਨੁਕਸਾਨਦੇਹ ਹੈ, ਤਾਂ side effects ਨੂੰ repeat-safe ਬਣਾਓ।\n- job row ਵਿੱਚ ਵੱਡੇ payloads ਰੱਖਣਾ। ਵੱਡੇ JSON blobs ਟੇਬਲ ਨੂੰ ਫੂਲ੍ਹਾ ਦਿੰਦੇ ਹਨ, indexes ਨੂੰ slow ਕਰਦੇ ਹਨ, ਅਤੇ locking ਨੂੰ ਭਾਰੀ ਬਣਾਉਂਦੇ ਹਨ। ਇੱਕ ਸੰਦਰਭ (ਜਿਵੇਂ
,
, ਜਾਂ file key) ਰੱਖੋ ਅਤੇ ਰਨ ਹੋਣ 'ਤੇ ਬਾਕੀ ਲਿਆਓ।\n\nਉਦਾਹਰਨ: ਤੁਸੀਂ weekly invoice ਈਮੇਲ ਭੇਜਦੇ ਹੋ। ਜੇ worker ਭੇਜਣ ਤੋਂ ਬਾਅਦ timeout ਹੋ ਜਾਵੇ ਪਰ job ਨੂੰ done ਮਾਰਕ ਕਰਨ ਤੋਂ ਪਹਿਲਾਂ, ਤਾਂ ਇਕੋ job ਮੁੜ retry ਹੋ ਸਕਦੀ ਹੈ ਅਤੇ duplicate ਈਮੇਲ ਜਨਮ ਲੈ ਸਕਦਾ ਹੈ। ਇਹ ਇਸ ਪੈਟਰਨ ਲਈ ਸਧਾਰਨ ਹੈ ਜਦ ਤੱਕ ਤੁਸੀਂ ਇੱਕ ਗਾਰਡਰੇਲ ਨਹੀਂ ਜੋੜਦੇ (ਉਦਾਹਰਨ ਲਈ,
ਤੇ keyed "email sent" event)\n\n### ਘੱਟ-ਸਪੱਸ਼ਟ ਗੋਟਚਾਸ\n\nਲੰਮੇ transaction ਵਿੱਚ scheduling ਅਤੇ execution ਮਿਲਾਉਣ ਤੋਂ ਬਚੋ। ਜੇ ਤੁਸੀਂ network calls ਦੌਰਾਨ transaction ਖੋਲ੍ਹੇ ਰੱਖਦੇ ਹੋ, ਤਾਂ ਤੁਸੀਂ ਲਾਕਜ਼ ਨੂੰ ਜ਼ਰੂਰਤ ਤੋਂ ਲੰਬੇ ਸਮੇਂ ਲਈ ਰੱਖ ਲੈਂਦੇ ਹੋ ਅਤੇ ਹੋਰ workers ਨੂੰ ਬਲਾਕ ਕਰਦੇ ਹੋ।\n\nਮਸ਼ੀਨਾਂ ਵਿਚਕਾਰ ਘੜੀ ਫਰਕਾਂ ਲਈ ਸਾਵਧਾਨ ਰਹੋ।
ਅਤੇ
ਲਈ database time (
in PostgreSQL) ਕੋ ਸਰੋਤ ਅਸਲ ਸਮਾਂ ਮਾਨੋ, ਐਪ ਸਰਵਰ ਘੜੀ ਨਹੀਂ।\n\nਸਾਫ਼ maximum runtime ਸੈੱਟ ਕਰੋ। ਜੇ ਇੱਕ job 30 ਮਿੰਟ ਲੈ ਸਕਦਾ ਹੈ, ਤਾਂ lease ਉਸ ਤੋਂ ਵੱਧ ਰੱਖੋ, ਅਤੇ ਜਰੂਰਤ ਹੋਏ ਤਾਂ renew ਕਰੋ। ਨਹੀਂ ਤਾਂ ਕੋਈ ਹੋਰ worker ਉਸਨੂੰ ਚਲਦਿਆਂ beech ਵਿੱਚ ਲੈ ਸਕਦਾ ਹੈ।\n\nਆਪਣੀ jobs ਟੇਬਲ ਸਿਹਤਮੰਦ ਰੱਖੋ। ਜੇ ਪੂਰੇ ਹੋਏ jobs ਹਮੇਸ਼ਾ ਲਈ ਜਮ੍ਹੇ ਰਹਿਣ, queries slow ਹੋ ਜਾਂਦੀਆਂ ਅਤੇ lock contention ਵੱਧ ਜਾਂਦੀ ਹੈ। ਟੇਬਲ ਵੱਡਾ ਹੋ ਜਾਣ ਤੋਂ ਪਹਿਲਾਂ ਇਕ retention ਨੀਤੀ (archive ਜਾਂ delete) ਰੱਖੋ।\n\n## ਤੁਰੰਤ ਚੈੱਕਲਿਸਟ ਅਤੇ ਅਗਲੇ ਕਦਮ\n\n### ਤੁਰੰਤ ਚੈੱਕਲਿਸਟ\n\nਇਸ ਪੈਟਰਨ ਨੂੰ ship ਕਰਨ ਤੋਂ ਪਹਿਲਾਂ ਬੁਨਿਆਦੀ ਚੀਜ਼ਾਂ ਚੈਕ ਕਰੋ। ਇੱਥੇ ਇੱਕ ਛੋਟੀ ਚੁੱਕੀ ਗਲਤੀ ਅਕਸਰ stuck jobs, duplicate, ਜਾਂ database 'ਤੇ ਹਮਲੇ ਵਾਲੇ worker ਬਣਾਉਂਦੀ ਹੈ।\n\n- ਤੁਹਾਡੀ jobs ਟੇਬਲ ਵਿੱਚ ਲਾਜ਼ਮੀ ਚੀਜ਼ਾਂ ਹਨ:
,
,
,
, ਅਤੇ
(ਨਾਲ
ਜਾਂ ਇਸੇ ਤਰ੍ਹਾਂ ਤਾਂਕਿ ਤੁਸੀਂ ਦੇਖ ਸਕੋ ਕਿ ਕੀ ਹੋਇਆ)।\n- ਹਰ job ਦੋ ਵਾਰੀ ਸੁਰੱਖਿਅਤ ਤਰੀਕੇ ਨਾਲ ਚਲ ਸਕਦਾ ਹੈ। ਜੇ ਤੁਸੀਂ ਪੱਕਾ ਨਹੀਂ ਹੋ, ਤਾਂ idempotency key ਜਾਂ side effect ਨੂੰ uniqueness rule ਸ਼ਾਮਲ ਕਰੋ (ਉਦਾਹਰਨ:
ਲਈ ਇੱਕ invoice).\n- ਫੇਲੀਆਂ ਨੂੰ ਦੇਖਣ ਅਤੇ ਫੈਸਲਾ ਕਰਨ ਲਈ ਇੱਕ ਸਪਸ਼ਟ ਥਾਂ ਹੈ: failed jobs ਦੇਖੋ, job ਨੂੰ ਦੁਬਾਰਾ ਚਲਾਓ, ਜਾਂ ਜਦੋਂ ਰੋਕਣਾ ਹੋਵੇ ਤਾਂ
ਮਾਰਕ ਕਰੋ।\n- ਤੁਹਾਡੀ lease (lock) timeout ਕੰਮ ਲਈ ਸੰਹੀ ਹੈ। ਇਹ ਆਮ ਚਲਾਉਣ ਲਈ ਲੰਮਾ ਹੋਣਾ ਚਾਹੀਦਾ ਹੈ, ਪਰ crash ਹੋਏ workers ਨੂੰ ਘੰਟਿਆਂ ਲਈ ਰੋਕਣ ਲਈ ਛੋਟਾ।\n- Retry backoff ਪੇਸ਼ਾਨਾ ਹੈ। ਇਹ ਦੁਬਾਰਾ ਫੇਲਯੋਗੀਆਂ ਨੂੰ ਹੌਲੀ ਕਰਦਾ ਹੈ ਅਤੇ
ਤੋਂ ਬਾਅਦ ਰੁਕਦਾ ਹੈ।\n\nਜੇ ਇਹ ਸੱਚ ਹੈ, ਤਾਂ ਕਰੋਨ + ਡੇਟਾਬੇਸ ਪੈਟਰਨ ਅਕਸਰ ਹਕੀਕਤੀ ਵਰਕਲੋਡ ਲਈ ਕਾਫ਼ੀ ਸਥਿਰ ਰਹਿੰਦਾ ਹੈ।\n\n### ਅਗਲੇ ਕਦਮ\n\nਚੈੱਕਲਿਸਟ ਠੀਕ ਹੋਣ 'ਤੇ, ਰੋਜ਼ਾਨਾ ਓਪਰੇਸ਼ਨ 'ਤੇ ਧਿਆਨ ਦਿਓ।\n\n- ਦੋ ਛੋਟੇ admin actions ਜੋੜੋ: “retry now” (
ਅਤੇ lock ਸਾਫ਼) ਅਤੇ “cancel” (terminal status ਵਿੱਚ ਭੇਜੋ)। ਇਨ੍ਹਾਂ ਨਾਲ incidents ਦੌਰਾਨ ਸਮਾਂ ਬਚਦਾ ਹੈ।\n- worker ਹਰ job ਲਈ ਇੱਕ ਲਾਈਨ ਲੌਗ ਕਰੇ: job type, job id, attempt number, ਅਤੇ result। growing failure counts 'ਤੇ alert ਜੋੜੋ।\n- ਇੱਕ ਹਕੀਕਤੀ spike ਨਾਲ load test ਕਰੋ: ਬਹੁਤ ਸਾਰੇ jobs ਇੱਕੋ ਮਿੰਟ ਲਈ schedule ਕੀਤੇ ਗਏ। ਜੇ claiming jobs slow ਹੁੰਦਾ ਹੈ, ਸਹੀ ਇੰਡੈਕਸ ਜੋੜੋ (ਅਕਸਰ