Skip to main content
Version: 0.6.1

Worker routing flows

How core and provider workers talk, as sequence and flow diagrams. They complement the provider contract: the contract states the rules, these show them in motion. A pool is every worker instance sharing one worker_name for one provider; a pool name is permanent and bound to one package.

ChannelSubject or key
Jobscairn.jobs.<job>.<provider>.<worker_name>
Resultscairn.results.<job>.<provider>.<worker_name>
Discoverycairn.discover.<provider>.<worker_name>
Account lookupcairn.accounts.lookup.<provider>.<worker_name>
Core releaseKV cairn_core/info
Rate budgetsKV cairn_rate_limits/<provider>.<app>.<window>

Routine import of an account​

The scheduler sends the reconcile to the account's pool. An unassigned account takes the provider's only known pool (the registry, not whoever happens to be online) and is then assigned to it. The worker sends its own fetch_source sub-jobs to its own pool and archives every parser input. Core checks each result against the sender's name on the subject, the pool's package, and the account's pool.

Pool registry, retirement and reassignment​

A pool is registered the first time its manifest or a result arrives; the name is then bound to that package. Admins retire a pool: it leaves routing and pickers, the name stays reserved, and the same package coming back un-retires it. The owner of a connection may move it to another pool: free within a package, with confirmation across packages, which flags the connection's activities pool_changed for a re-fetch.

Re-parse while a pool is mid-upgrade​

Core picks the newest live parser of the source's own package and dataset, and puts the source's current parser version in the job. An older instance that still pulls the job hands it back with growing delay; after ten deliveries it reports parser_too_old, and core keeps the source flagged instead of failing it. Core refuses any result that would lower the version.

Two worker implementations for one provider​

Each pool has its own job and result subjects, so the work queue never sees overlapping consumers and a pool cannot publish as another. The matcher allows one source per pool, so an API import and a FIT import of the same ride cluster into one activity. A merge priority entry may name a pool as garmin.garmin-fit; a bare garmin covers every pool.

Two connections for one provider account​

A provider account may be connected once per pool; a pool the user does not want is simply not connected. Each connection has its own sync state, queue, tokens and app. A gear id decided on one connection maps the sibling's reference too.

Webhook event to account​

A webhook names the provider's owner id. The worker asks on its own pool's lookup subject; the subject (which it is permitted to publish on) names the pool, so core returns that pool's connection and another pool cannot look it up. A connection without a pool matches any pool.

Rate budgets per provider app​

OAuth apps belong to connections, and one pool serves many of them. Core names the app in the token reply (app_id, a hash of the client id); the worker attributes usage headers, 429s and reservations to that app's buckets. Core reads the same keys to gate reconcile and to show the budget per connection. A token without an app id falls back to the pool's bucket.

Release compatibility​

Core publishes its release in the cairn_core KV bucket (workers can only read it). Before 1.0 a worker needs the same major.minor. From 1.0 on, minor and patch releases are backwards compatible: same major, and the worker's minor not above core's. A worker refuses to start, and stops on its next heartbeat, against an incompatible core; core also flags such workers and ignores them for re-parse and gear routing. Untagged builds skip the check.

Upgrade from 0.4: draining queued jobs​

Jobs queued on the old provider-only subjects before the upgrade are not lost: the permission template still lets the pool subscribe to them with its old durable name. Results and lookups are pool-scoped only. The grant was meant to last one minor release but is still present in 0.6.0; a later release removes it.

Bulk re-parse after a parser release​

A new parser flags every source of its pool and dataset as update_available / newer_parser; a new dataset flags newer_dataset (re-fetch only). The Connections page shows the counts, and one action re-parses up to 500 sources without provider quota.