Skip to Content

Best practices to design Odoo crons

Duration: 22:39


PART 1 — Analytical Summary 🚀

Context 💼

This talk, led by an internal Odoo platform developer, distills hard‑earned lessons from operating large-scale Scheduled Actions (crons) across many databases. The goal: ensure your cron jobs don’t get silently deactivated in Odoo 18+ or spin forever wasting CPU pre-18. Two real-world scenarios frame the discussion—subscription invoicing and Google/Microsoft calendar sync—showing how naïve implementations fail and what modern Odoo APIs offer to fix them.

Core Ideas & Innovations ⚙️

A cron in Odoo is a database record (scheduled action) that runs a Python method on a cadence. From v17/18 onward, you can even programmatically trigger them via a dedicated API. The talk’s central message is that robust cron design depends on three pillars: being idempotent, incremental, and robust, then refined with being complete, bounded, splitable, and verbose.

The biggest behavioral shift arrives in Odoo 18’s deactivation logic: if a cron fails 5 times in a row across at least 7 days (with 3 timeouts counting as failures), or if it hits 15 timeouts, it gets disabled—unless it reports progress. That’s where the two progress APIs matter. In v18, use notify_progress(done, remaining); in v19, use the newer commit_progress, which also commits for you and lets you declare “remaining” once, then report processed counts in batches. Reporting even minimal progress (done > 0) means a timeout is no longer counted as a failure; if there’s still work left (remaining > 0), Odoo reschedules the cron to run again ASAP. In v19, commit_progress also returns whether you have time left—falsy means “wrap up and let the scheduler resume later.”

Two canonical use cases underscore why design matters. For subscription invoicing, idempotency is enforced by tracking a next_invoice_date and only selecting records due “today,” then pushing the date forward after success—so retriggers don’t double invoice. For calendar sync, idempotency is ensured at the sync layer by deduplication with the external provider. Both jobs must use incremental batching with per-batch commits to avoid long transactions, locks, and rollbacks on timeouts. To keep transactions short and stable, the talk stresses committing only once a record is fully processed—especially important when external APIs are involved to prevent inconsistencies (e.g., payment captured externally but rolled back internally).

Robustness comes from catching relevant exceptions, rolling back the failed record cleanly, and continuing with the rest. However, because caught errors can “hide,” the speaker urges detailed logging, including tracebacks. To ensure completeness, the system should naturally retry records affected by temporary issues (e.g., “process today and in the past” for invoicing). To avoid retrying bad records forever—and getting deactivated by useless timeouts—make crons bounded by tracking failures (e.g., an error_count for sync users) and excluding records that exceed a threshold, or by limiting how far back you retry (e.g., 10–15 days). The trade-off is clear: boundedness reduces completeness, so you must surface these records for manual intervention via filters or views (e.g., “next_invoice_date older than 15 days” or “error_count > threshold”).

Finally, make crons splitable. Accept an optional list of ids in your method and create multiple cron definitions that shard data deterministically (e.g., id modulo) or by business dimension (e.g., region). This enables parallelism or timezone-friendly schedules, but demands careful lock design (e.g., posting in the same journal can cause contention). For testing, instead of adding “if test: don’t commit” branches, rely on the platform’s test cursor and “enter register test mode,” which neutralizes commits during tests so production code can remain realistic.

Impact & Takeaways 🧠

The net effect is a simpler, safer, and more scalable cron architecture across Odoo 18/19:

  • Idempotent patterns prevent duplicate work and inconsistent states, enabling safe retries and manual runs.
  • Incremental, batch-based commits reduce timeouts, lock contention, and full-transaction rollbacks.
  • Progress APIs (notify_progress, commit_progress) keep long-running jobs alive, reschedule ASAP when needed, and prevent deactivation.
  • Robust-but-bounded strategies ensure healthy throughput, avoid endless retries, and surface hard failures for human resolution.
  • Splitable designs unlock parallelism and operational scheduling flexibility.
  • Cleaner tests via test-mode commit neutralization remove brittle test conditionals in business code.

Practical details from Q&A round out the guidance: avoid safe points in loops (they cause Postgres and replication issues), choose batch sizes case-by-case, recognize DST shifts because cron times are stored in UTC, and note that on Odoo.sh there is a dedicated cron worker. The single most important habit? Report and commit your progress. 💬

PART 2 — Viewpoint: Odoo Perspective

Disclaimer: AI-generated creative perspective inspired by Odoo's vision.

Our philosophy has always been straightforward: make complex things simple. With crons, that means designing for idempotency, short transactions, and clear progress signals. When your jobs tell the system what they’ve achieved, Odoo can orchestrate the rest—rescheduling intelligently and avoiding wasted cycles.

The new progress APIs in 18 and 19 are small features with big leverage. They let developers focus on business logic while the platform handles resilience. And by keeping everything integrated—from invoicing to calendar sync—we reduce the hidden costs of distributed failure modes. It’s not about more knobs; it’s about fewer surprises for everyone, including the community that builds on Odoo.

PART 3 — Viewpoint: Competitors (SAP / Microsoft / Others)

Disclaimer: AI-generated fictional commentary. Not an official corporate statement.

Odoo’s guidance on idempotency, batching, and progress signaling aligns with job orchestration best practices we see in larger ecosystems. The move to platform-level deactivation and resume semantics, coupled with commit_progress, is a pragmatic step toward operational reliability. For SMEs it’s a strong developer experience with coherent defaults and a good UX for recovery.

At scale, the usual questions remain: end-to-end observability, fine-grained SLAs across distributed workers, compliance-grade audit trails, and guardrails for parallelism conflicts. Enterprises often seek deeper segregation of duties and richer policy controls across regions. Even so, Odoo’s approach provides a clean blueprint—especially for teams without dedicated platform engineers—and a noteworthy balance between simplicity and resilience.

Disclaimer: This article contains AI-generated summaries and fictionalized commentaries for illustrative purposes. Viewpoints labeled as "Odoo Perspective" or "Competitors" are simulated and do not represent any real statements or positions. All product names and trademarks belong to their respective owners.

Share this post
Archive
Sign in to leave a comment
The Future of the CFO in the Digital Age