October 10th, 2026

Odoo scheduled actions: write one that does not hang your server

A scheduled action (ir.cron) runs in a background worker. A bad one holds a database lock and blocks users.

Define it

<record id="cron_sync_prices" model="ir.cron">
    <field name="name">Sync prices</field>
    <field name="model_id" ref="product.model_product_template"/>
    <field name="state">code</field>
    <field name="code">model._cron_sync_prices()</field>
    <field name="interval_number">1</field>
    <field name="interval_type">days</field>
</record>

Work in batches

@api.model
def _cron_sync_prices(self, batch=200):
    todo = self.search([('price_dirty', '=', True)], limit=batch)
    for rec in todo:
        rec._sync_price()
    if len(todo) == batch:
        self.env.ref('mymodule.cron_sync_prices')._trigger()
    self.env['ir.cron']._commit_progress(len(todo))  # Odoo 18+

_trigger() schedules another run right away, so one run never holds a huge transaction.

Rules

  • Make the work idempotent. Running twice must not double-count.
  • Never loop over every record without a limit.
  • Log how many records you handled.
  • Test it from Settings → Technical → Scheduled Actions → Run Manually.

← All posts