Configuration

Topic (ip.topic)

A topic (ip.topic) is the primary configuration object. It wires together:

  • the schema (ip.schema) defining the bidirectional JSON ↔ Odoo mapping,

  • the swarms that receive or produce events on this topic,

  • the export triggers (instant automation or scheduled cron),

  • the import cadence (instant or batch cron),

  • the delivery mode (push or pull) and retry count,

  • a garbage-collection domain (ip.topic.delete_domain) for pruning old events.

Topics auto-create and self-heal their base.automation and ir.cron records; manual activation of a managed cron is blocked to prevent conflicts.

Note

A topic on a staging or development database is automatically neutralized: its outbound automations are disabled so test data cannot reach production peers. Re-enable them explicitly before using the database as a live node.

See also

Technical references — sync_base.ip.topic, sync_kubo.ip.topic.


Auto-managed Infrastructure

When you save a topic, ip.topic._sync_infra() creates or updates:

  • a base.automation (for export_mode = instant), and

  • one or more ir.cron records (for batch export, batch import, delivery, and GC).

These records are self-healing: if you delete or disable one, the topic recreates it on the next save.

Warning

Manually disabling a topic-managed cron is not persistent — base.automation.write() and ir.cron.write() both enforce an activation guard that raises a UserError if you try to re-enable a managed record directly. To pause all activity on a topic, use the topic’s Active toggle or archive the record.


Export

On each export run the automation or cron selects records matching ip.topic.export_domain, passes them through ip.schema._to_payload(), and creates one ip.event per record (or per batch when ip.topic.event_array_size > 1) with direction='outbound' and routing_state='pending'.

Field

Effect

ip.topic.export_mode

Instant: Creates an event instantly when a record is saved.
Batch: A cron job sweeps records periodically to generate events.

Use instant for low-volume, latency-sensitive data, and batch when throughput matters more than latency.

ip.topic.export_domain

Defines which Odoo records are candidates for auto-export.
- Batch: The export cron sweeps records matching this domain.
- Instant: The automation synchronously triggers for records matching this domain.
Once an event is created, this domain won’t restrict it from being sent.

Leave empty to export every record of the target model.

ip.topic.export_batch_size

Maximum number of outbound ip.event payloads to generate per export run (0 = no limit).
If payload type is ‘Array’, the export will sweep (Batch Size x Array Size) Odoo records per run.

ip.topic.event_array_size

Maximum number of Odoo records per ip.event of type ‘array’.

See Data Schema for "object" vs "array" root types.

ip.topic.export_context_action_id

Server action bound to the model’s Action menu for manual record-level export.

Hook — ip.topic.export_server_action_id runs after events are generated, with the exported records as active_ids in context. Use it to stamp a synced flag or trigger downstream logic. To prevent an infinite export cycle, export crons are not re-triggered if the exported records still match the export_domain after running that action. To trigger a sync export from any server action, set its state to sync_send — this invokes ir.actions.server._run_action_sync_send().

Tip

Never point export_server_action_id at another sync_send action — the topic detects the loop and raises a ValidationError.

Note

On a database with no live gateway node (staging, dev), outbound automations are disabled automatically. Re-enable the automation or re-set export_mode to trigger ip.topic._sync_infra() before going live.

Export & Send — action_run_export_deliver()

Generates events from records matching ip.topic.export_domain then immediately dispatches them in one step. Bypasses auto_export, ip.topic.auto_deliver, and pull-mode restrictions. The most common manual trigger.

Export (batch mode) — action_run_export()

Visible only when export_mode = batch. Generates events and parks them in routing_state: pending without pushing to the network. Use to stage events before delivery.


Import

On each import run the engine calls ip.event._try_mapping() on pending inbound events, running the schema AST in three passes: scan lookups, bulk ORM search, then assemble and execute create/write calls.

Field

Effect

ip.topic.import_mode

Instant: Maps inbound events immediately in ip.event.create() when domains match.
Batch: Events are parked as pending and mapped by the import cron.

Use instant for low-volume, latency-sensitive data; batch reduces cron overhead for high-volume topics (the three-pass DataLoader already batches ORM calls internally).

ip.topic.import_batch_size

Maximum number of events to ingest per cron execution (0 = no limit).

ip.topic.auto_import

Automatically map inbound events to records.

When False (default True), inbound events keep ip.event.mapping_state as ignored — useful for outbound-only topics or manual review before import.

Hook — ip.topic.import_server_action_id fires after the schema engine successfully maps inbound events to Odoo records, with the created or updated records as active_ids in context. Use it to send emails, update related models, or trigger other downstream business logic.

Import — action_run_import()

Sweeps pending inbound events for this topic and maps them into Odoo records, up to ip.topic.import_batch_size. Bypasses cron guards and does not re-trigger the import cron.


Delivery

The postman ir.cron polls for events with routing_state = pending and dispatches them via ip.swarm._dispatch_events(). With ip.topic.deliver_mode = push the gateway POSTs to each peer directly; with pull peers call /v0/pull on their own schedule.

Field

Effect

ip.topic.deliver_mode

Determines how pending events reach the Gateway.
PUSH: Odoo actively sends events to the Gateway.
- Auto-Deliver ON: Dispatched instantly. Failures are retried by the Global Postman.
- Auto-Deliver OFF: Requires manual dispatch. Failures are NOT retried.
PULL: The Gateway continuously polls Odoo for events.
- Auto-Deliver ON: The Gateway is permitted to fetch pending events.
- Auto-Deliver OFF: The Gateway is blocked. You must manually force a push.

Use push when peers are directly reachable (low latency), and pull for firewall-friendly or offline-first topologies.

ip.topic.routing_mode

How the topic routes events:
- Broadcast (all): multi-node broadcast to all peers in active swarms with at-most-once delivery.
- Direct (p2p): targeted point-to-point delivery to specific nodes resolved by __nodes__ in payload.

Use direct (see __nodes__ in Odoo Schema) for request-response patterns or per-record ownership, as opposed to broadcast.

ip.topic.deliver_batch_size

Maximum number of events to dispatch per cron run (0 = no limit). Actual batch may be smaller when concurrent deliveries lock events for sending.

ip.topic.deliver_retries

If disabled, events are only sent once.
- Push: The Global Postman will not attempt to resend if the Gateway is offline.
- Pull: Odoo will not re-serve the events if the Gateway crashes before confirming them.
Ideal for high-volume transient data.

When True (default), retries events stuck in sending state after a 2-minute timeout.

ip.topic.auto_deliver

If enabled, events generated by this topic are automatically queued for delivery. If disabled, events remain ‘pending’ until you manually click ‘Run Delivery’ (push).

Run Postman — action_run_deliver()

Sweeps all pending or stalled outbound events in this topic’s outbox and pushes them to the gateway. Bypasses the pull-mode restriction so admins can force-push events that are normally polled. Does not re-trigger the global postman cron.


Delete

A GC ir.cron runs periodically when ip.topic.auto_delete = True, applying ip.topic.delete_domain to prune old ip.event records and keep table growth bounded.

Field

Effect

ip.topic.auto_delete

Automatically delete old events in this topic matching a specific domain.

ip.topic.delete_domain

Events in this topic matching this domain will be unlinked by the Garbage Collection cron.
Context variables: datetime, timedelta, relativedelta, context_today, env.

The default retains events for 7 days and only prunes fully delivered or mapped ones (see below).

Default delete_domain:

[
    ('write_date', '<', context_today() - relativedelta(days=7)),
    '|', '|',
        '&', ('direction', '=', 'inbound'), ('mapping_state', '=', 'mapped'),
        '&', ('direction', '=', 'inbound'), '&', ('mapping_state', '=', 'ignored'), ('mapping_info', '=', False),
        '&', ('direction', '=', 'outbound'), ('routing_state', '=', 'sent')
]

The 7-day window gives offline peers time to catch up and leaves a debugging window. Override ip.topic.delete_domain to retain specific events for audit purposes rather than disabling ip.topic.auto_delete entirely.

Run Collector — action_run_delete()

Immediately evaluates ip.topic.delete_domain against this topic’s events and permanently unlinks matching records. Does not re-trigger the global collector cron.