Documentation / Exploitation / Guides pratiques / Connect an event source and activate bindings

Connect an event source and activate bindings

This recipe wires up event-driven ingestion on a running instance: point a source mechanism (e.g. fhir-poll) at a real endpoint, then decide which of the bindings contributed by your plugins are allowed to fire. As an operator you own the connection — the sources: and eventBindings: blocks of the instance manifest (libs/shared/src/plugin/instance.ts). The query each binding runs and the map it uses to project a raw record into a domain event are authored by the plugin, not configured here — see Contribute an event source and binding and The open event model for that side.

Before you start

  • The plugin contributing the source mechanism and the bindings you want must already be installed — see Declare and install plugins. Sources and bindings are plugin contributes.eventSources / contributes.eventBindings entries (libs/shared/src/plugin/manifest.ts); the instance can only activate what a loaded plugin contributes, never invent one.

  • You need the exact name of each binding and the source mechanism it targets. List what's loaded:

    curl -s http://localhost:4000/api/plugins | jq '.[].contributes.eventBindings'
    

    or read the plugin's plugin.yaml directly. For example, external-plugins/fhir/plugin.yaml contributes one mechanism, fhir-poll (external-plugins/fhir/sources/poll.ts), and several bindings on top of it — fhir-creatinine, fhir-medication-prescribed, fhir-patient-admitted, fhir-patient-discharged, fhir-allergy-recorded, fhir-communication-received, fhir-condition-recorded, plus one resolve-style binding, fhir-validation-decided, that resumes suspended runs instead of starting new ones.

1. Configure the source connection

Add an entry under sources: in the instance manifest, keyed by the mechanism's name (not a binding's name). The value is an opaque config object passed straight through to the mechanism's factory as SourceFactoryOpts.config (libs/shared/src/plugin/source.ts) — its shape is whatever that specific mechanism reads, not something the core validates.

For the bundled fhir-poll mechanism, the recognized keys are baseUrl, intervalSeconds (poll period, default 15) and count (page size, default 50):

sources:
  fhir-poll: { baseUrl: http://localhost:8090/fhir, intervalSeconds: 15 }

A source is only instantiated if at least one of its bindings ends up active in step 2 — configuring a connection for a mechanism with no active binding is a harmless no-op, not an error.

2. Choose which bindings are active

By default, every binding whose source was configured in step 1 is active — you get all of them. To activate only a subset, add an eventBindings: allowlist naming the bindings you want, by name:

eventBindings: [fhir-creatinine, fhir-medication-prescribed]

Omit the key entirely to keep everything available on the configured sources active — this is the shipped default in instance.yaml and instance.example.yaml, which both leave eventBindings commented out. The rule is applied verbatim in startEventSources (apps/api/src/server/api.ts): a binding is active only if its source has a sources: entry and (no allowlist is set, or the binding's name is in it).

3. Restart the API

The instance manifest is read once at boot (apps/api/src/instance.ts, loadInstance — the INSTANCE_CONFIG env var if set, else instance.yaml at the repo root), and startEventSources() runs once, right after the HTTP listener comes up (apps/api/src/server/api.ts). Changes to sources: or eventBindings: are not hot-reloaded — restart the API process to pick them up.

Verify

  • Watch the boot logs for the sources component: a successful start logs source démarrée with the source name and the active feed names; a source name with no matching mechanism logs mécanisme de source introuvable; a factory that throws on start() logs démarrage échoué (all three from startEventSources in apps/api/src/server/api.ts).
  • Confirm real traffic turns into activity: watch GET /api/runs for new runs after data lands upstream, or check the clinical.events.generated counter (attributes source, feed, event, outcome) for outcome: "accepted" — see Enable observability.
  • For a resolve binding — it resumes a suspended validation instead of starting a run, see Add human validation — confirm the targeted run leaves its pending state once the upstream decision lands.

Troubleshooting

  • No sources logs at all: startEventSources returns early when zero bindings are active. Confirm sources: is keyed on the mechanism's name (e.g. fhir-poll), not on a binding's name.
  • mécanisme de source introuvable: the source a binding points to isn't contributed by any loaded plugin. Confirm the plugin is installed and double-check the exact source name via GET /api/plugins.
  • A binding you expected is silently inactive: it's excluded by your eventBindings: allowlist, or its source has no matching key under sources:. Both are matched by exact string equality — a typo doesn't error, it just leaves the binding off.
  • démarrage échoué for fhir-poll: the factory throws synchronously if baseUrl is missing from both config.baseUrl and the FHIR_BASE_URL environment variable (external-plugins/fhir/adapters/client.ts, resolveBaseUrl) — add baseUrl under the fhir-poll entry.
  • Source is polling but no runs appear: the binding's map may be failing (projection (map) échouée, counted as a rejected generation) or the projected event type has no workflow trigger claiming it (ingestEvent rejects with "Aucun déclencheur ne revendique l'événement…"). Both are plugin/workflow authoring concerns, not instance configuration — see Contribute an event source and binding and Workflow DSL.
75 documents7 sectionssource : /docs · généré au build