Skip to main content

Crate photon

Crate photon 

Source
Expand description

Pub/sub event pipeline facade.

Typed topics, durable subscriptions with checkpoints, and the same API in single-process and multi-node deployments. Enable the runtime feature for the full stack (Photon, backends, executor). Photon uses pluggable storage adapters (mem, sqlite, nats, fluvio, kafka) behind StoragePort and Quark inventory for topic/handler discovery. Payloads are encrypted before append; storage stays opaque. Canonical business data remains in your datastore — the transport log is for event delivery, not system of record.

§Features

  • Typed topics and handlerstopic / subscribe register via Quark inventory
  • Same API everywherepublish_on / start_executor whether you run one process or many
  • Pluggable storagemem, sqlite, or broker adapters (nats, kafka, fluvio)
  • Durable subscriptions — checkpointed replay after restart on durable adapters
  • Host-owned cryptoPHOTON_TRANSPORT_KEY encrypts envelopes before they hit storage

Typed pub/sub over a persistent event log — pick embedded or brokered topology.

§Getting started

You always publish and subscribe the same way (OrderCreated { … }.publish_on(&photon), #[subscribe], Photon::start_executor). What changes is whether events stay in one process or cross a broker to another binary.

§Choose a topology

  • Mode 1 — Embedded — one process owns publish and handlers. Start here (mem or sqlite).
  • Mode 2 — Brokered — publisher binary(ies) and worker binary(ies) share a broker. Photon does not ship a separate server binary; each process embeds Photon against the same adapter.
TopologyAdapterFeaturesWhen to use
EmbeddedInProcStoragePort (default)runtime,memLocal / tests
Embedded durableSqliteStoragePortruntime,sqliteSingle host, restart-safe
BrokeredNATS / Kafka / Fluvioruntime + nats/kafka/fluvioMulti-process / fleet

Adapter builders and env vars: config.

After you pick a mode, continue with declare topics.

§Mode 1 — Embedded (one binary)

This process publishes and runs handlers. There is no second binary and no external broker.

Your app ──publish / #[subscribe]──► Photon ──StoragePort──► mem | sqlite

Prerequisites: Cargo features runtime + mem (or sqlite), and PHOTON_TRANSPORT_KEY (base64 of 32 bytes). See config.

In-memory (default — PhotonBuilder installs InProcStoragePort when you omit storage_port):

use std::sync::Arc;

use photon::{JsonIdentityFactory, Photon};

let photon = Photon::builder().auto_registry().build()?;
photon.start_executor(Arc::new(JsonIdentityFactory))?;
// Prefer EventType { … }.publish_on(&photon).await

SQLite — durable single-process (write-through + in-memory live fanout):

use std::sync::Arc;

use photon::{JsonIdentityFactory, Photon, SqliteStoragePort};

let port = Arc::new(SqliteStoragePort::open("/var/lib/photon/events.db").await?);
let photon = Photon::builder()
    .storage_port(port)
    .auto_registry()
    .build()?;
photon.start_executor(Arc::new(JsonIdentityFactory))?;

Runnable: cargo run -p uf-photon --example embedded_mem --features runtime,mem. Then jump to declare topics.

§Mode 2 — Brokered (publisher + worker binaries)

Use this when multiple processes (or hosts) must share the same topic log. mem and sqlite cannot fan out across processes — wire a broker adapter instead.

Publisher binary  ──publish_on──► Photon ──StoragePort──► broker (NATS / Kafka / Fluvio)
Worker binary     ──start_executor / #[subscribe]──► Photon ──same broker──►

§What you create

PiecePurpose
Shared topicsSame #[topic] types (shared crate or both binaries compile them)
Publisher binary[[bin]] that publishes; typically no start_executor
Worker binary[[bin]] with #[subscribe] handlers; must call start_executor
BrokerNATS / Kafka / Fluvio cluster your ops team runs
Shared envSame PHOTON_TRANSPORT_KEY + broker URL (e.g. PHOTON_NATS_URL) on every process

§Shared setup (both binaries)

  1. Enable runtime plus one broker feature (nats is the usual first choice).
  2. Build the same storage port against the same cluster — pick a builder below.
  3. Call .auto_registry() when using macros.
  4. Keep the Photon handle for publish_on / subscribe_on.
AdapterFeatureBuilder (publisher + worker examples)
NATSnatsNatsStoragePortBuilder
KafkakafkaKafkaStoragePortBuilder
FluviofluvioFluvioStoragePortBuilder

Env index: config. NATS sketches follow; swap the builder for Kafka/Fluvio.

§Publisher binary

Wire the broker port, declare topics, publish. Skip Photon::start_executor unless this process also handles events.

use std::sync::Arc;

use photon::{Photon, NatsStoragePort, ReplayCursor};

let port = Arc::new(
    NatsStoragePort::builder()
        .from_env_defaults()
        .replay_cursor(ReplayCursor::StreamSeq)
        .sync_ack(true)
        .build()
        .await?,
);
let photon = Photon::builder()
    .storage_port(port)
    .auto_registry()
    .build()?;
// OrderCreated { … }.publish_on(&photon).await?;

§Worker binary

Same storage port wiring as the publisher, plus #[subscribe] handlers and Photon::start_executor:

use std::sync::Arc;

use photon::{JsonIdentityFactory, Photon, NatsStoragePort, ReplayCursor};

let port = Arc::new(
    NatsStoragePort::builder()
        .from_env_defaults()
        .replay_cursor(ReplayCursor::StreamSeq)
        .sync_ack(true)
        .build()
        .await?,
);
let photon = Photon::builder()
    .storage_port(port)
    .auto_registry()
    .build()?;
photon.start_executor(Arc::new(JsonIdentityFactory))?;

§Run both

  1. Start the broker.
  2. Start worker(s) first so subscriptions are ready.
  3. Start one or more publishers.

Then continue with declare topics.

§3. Declare topics and handlers

  • topic — typed event struct + inventory registration; generates publish_on / subscribe_on
  • subscribe — inventory-registered handler; requires Photon::start_executor on workers
  • prelude — common imports (Event, SubscribeOpts, Photon, macros)

Attribute tables: config. Runnable: keyed_topic, consumer_group, subscribe_v2.

§4. Publish and subscribe

After topic, the macro generates typed methods on your event struct. Prefer those over raw Photon::publish / Photon::subscribe.

Publishpublish_on with an explicit Photon handle:

OrderCreated {
    order_id: "ord-1".into(),
    amount_cents: 9900,
}
.publish_on(&photon)
.await?;

Typed streamsubscribe_on (no #[subscribe] / executor required):

use futures::StreamExt;
use photon::SubscribeOpts;

let opts = SubscribeOpts::default_ephemeral();
let mut stream = OrderCreated::subscribe_on(&photon, opts).await?;
if let Some(Ok(envelope)) = stream.next().await {
    let _payload = envelope.payload; // OrderCreated
}

Inventory handlers#[subscribe] + Photon::start_executor (Mode 1 / Mode 2 workers).

Optional sugar after configure: .publish() / .subscribe() without a handle. Raw topic-name API (advanced): Photon::subscribe.

Runnable: embedded_mem (publish_on + #[subscribe]), keyed_topic (subscribe_on), manual_subscribe (raw Photon::subscribe).

§5. Run the executor and reclaim

§Notes

  • Transport key: boot fails closed without a valid PHOTON_TRANSPORT_KEY (see config).
  • Durable multi-process: use a broker adapter; mem does not cross process boundaries.
  • Lab topologies: testkit / bench PHOTON_TOPOLOGY values are harness labels — not the Mode 1 / Mode 2 product choices above.
  • Custom adapters: implement StoragePort and pass it to PhotonBuilder::storage_port. Advanced delivery traits live behind that port.

§Architecture

Application  →  Photon (macros + Photon runtime)  →  storage port  →  delivery backend
  Typed API (#[topic], publish_on / publish, #[subscribe])
             │
             v
  Photon runtime
             │
             v
        StoragePort  ──►  mem (InProcStoragePort)
                     ──►  sqlite (SqliteStoragePort)
                     ──►  nats / fluvio / kafka (broker crates)
                     ──►  custom implementation

Full option reference: config. Macro expansion: repository docs/macro-expansion.md.

Re-exports§

pub use quark::inventory;

Modules§

backend
Backend implementations and assembly context for Photon.
backend_instrumentation
Backend instrumentation (L0 publish telemetry + ops log helpers).
checkpoint
Checkpoint coalescing for durable subscriptions.
config
Photon configuration reference
consumer_group
Consumer group coordination: shard assignment and leases.
delivery
Handler delivery: backpressure and dead-letter queue.
delivery_mode
Topic delivery mode and virtual shard configuration.
descriptor
Topic descriptor for auto-registration.
error
Error types for Photon.
event
Event envelope encryption.
handler_ctx
Delivery metadata injectable into #[photon::subscribe] handlers (v2).
handler_descriptor
Handler descriptor for #[photon::subscribe] inventory registration.
handler_registry
Registry of #[photon::subscribe] handlers discovered via inventory.
host
Host-facing runtime wiring (executor bootstrap).
instrumentation
Photon platform observability via injected photon_telemetry::OpsLog.
models
In-memory models for Photon entities.
prelude
Common imports for application code using typed topics and the runtime handle.
registry
Topic registry for discovering and looking up registered topics.
runtime_parts
Host-facing runtime wiring helpers (Integrating the host).
shard_router
Virtual shard routing for consumer-group topics.
storage
Storage adapter port — one implementation per --storage tier (mem, sqlite, nats, fluvio, kafka).

Macros§

actor_downcast_methods
Re-export identity port traits and JSON stubs from photon_core. Expands the standard Actor Any downcast method bodies.

Structs§

AdminBackendSummary
Storage adapter capabilities surfaced for admin UIs.
AdminCheckpointSummary
Last committed sequence for a subscription/topic partition.
AdminHandlerSummary
Inventory entry for a #[photon::subscribe] handler.
AdminSnapshot
Point-in-time ops introspection snapshot (read-only).
AdminTopicSummary
Topic catalog entry from the compile-time TopicRegistry.
BackendCapabilities
Capabilities advertised by a storage port (surfaced via crate::backend::GenericPhotonBackend).
BackendContext
Shared builder context for storage adapter install fns.
ConsoleOpsLog
stderr/stdout structured lines (default dev adapter).
Envelope
Event envelope with decoded payload.
Event
Published event with payload and metadata.
FluvioConfig
Resolved Fluvio adapter settings (no env lookups at append time).
FluvioStoragePort
Fluvio-backed storage port.
FluvioStoragePortBuilder
Builder for super::port::FluvioStoragePort.
GenericPhotonBackend
Unified backend — all storage adapters install this wrapping their port.
GroupOpts
Options specific to consumer-group subscriptions.
HandlerCtx
Delivery metadata for a single handler invocation.
HandlerDescriptor
Descriptor for a #[photon::subscribe] handler (inventory + executor dispatch).
HandlerRegistry
Registry of inventory-submitted subscription handlers.
InProcStoragePort
In-process storage for the mem adapter tier.
JsonActor
Re-export identity port traits and JSON stubs from photon_core. Actor label derived from publish-time actor_json (System.operation when present).
JsonIdentityFactory
Re-export identity port traits and JSON stubs from photon_core. Reconstructs JsonActor from JSON captured at publish time.
KafkaConfig
Resolved Kafka adapter settings (no env lookups at append time).
KafkaStoragePort
Kafka-backed storage port.
KafkaStoragePortBuilder
Builder for super::port::KafkaStoragePort.
NatsConfig
Resolved NATS adapter settings (no env lookups at append time).
NatsStoragePort
NATS JetStream-backed storage port.
NatsStoragePortBuilder
Builder for super::port::NatsStoragePort.
NoOpsLog
Zero-cost no-op (benchmark telemetry=off and minimal CI).
Photon
Main Photon runtime handle.
PhotonBuilder
Builder for constructing Photon runtimes.
PhotonRuntimeState
Shared storage port, executor services, and handler dispatch controller.
ShardConfig
Virtual shard settings for DeliveryMode::ConsumerGroup topics.
SqliteStoragePort
Embedded SQLite storage for the sqlite adapter tier.
SubscribeOpts
Options for subscribing to a topic.
Subscription
Subscription handler registration.
SubscriptionHandle
Placeholder for future subscription lifecycle control (cancel, pause).
TopicDescriptor
Descriptor for a registered topic (from #[photon::topic] macro).
TopicMetadata
Topic metadata stored in the registry.
TopicRegistry
Registry of all topics discovered via #[photon::topic].
TransportCrypto
Symmetric payload encryption (XChaCha20-Poly1305).

Enums§

DeliveryMode
How publishes on a topic are routed to subscribers.
FluvioReplayCursor
How durable replay and checkpoints map to Fluvio offsets.
IdentityError
Re-export identity port traits and JSON stubs from photon_core. Errors from crate::IdentityFactory::reconstruct.
KafkaReplayCursor
How durable replay and checkpoints map to Kafka offsets.
PhotonError
Errors that can occur in Photon operations.
ReplayCursor
How durable replay and checkpoints map to JetStream.
SubscriptionMode
Subscription mode.

Constants§

FLUVIO_ENDPOINT_ENV
Environment variable for Fluvio SC endpoint.
FLUVIO_MAX_INFLIGHT_ENV
Environment variable for max in-flight publishes per port.
FLUVIO_PREFIX_ENV
Environment variable for topic name prefix.
FLUVIO_REPLAY_CURSOR_ENV
Environment variable for replay cursor mode.
FLUVIO_REPLICAS_ENV
Environment variable for topic replication factor.
FLUVIO_RETENTION_ENV
Environment variable for Fluvio topic retention.
FLUVIO_SYNC_ACK_ENV
Environment variable for synchronous publish ack (1 / 0).
FLUVIO_TOPIC_SHARDS_ENV
Environment variable for topic shard count (bench/scripts fallback).
KAFKA_BROKERS_ENV
Environment variable for Kafka bootstrap brokers.
KAFKA_MAX_INFLIGHT_ENV
Environment variable for max in-flight publishes per port.
KAFKA_PREFIX_ENV
Environment variable for topic name prefix.
KAFKA_REPLAY_CURSOR_ENV
Environment variable for replay cursor mode.
KAFKA_REPLICAS_ENV
Environment variable for topic replication factor.
KAFKA_RETENTION_ENV
Environment variable for Kafka topic retention.
KAFKA_SYNC_ACK_ENV
Environment variable for synchronous publish ack (1 / 0).
KAFKA_TOPIC_SHARDS_ENV
Environment variable for topic shard count (bench/scripts fallback).
MAX_INFLIGHT_ENV
Environment variable for max in-flight publishes per port.
NATS_RETENTION_ENV
Environment variable for JetStream stream retention.
NATS_STREAM_ENV
Environment variable for JetStream stream name.
NATS_STREAM_SHARDS_ENV
Environment variable for stream shard count (bench/scripts fallback).
NATS_URL_ENV
Environment variable for NATS server URL.
REPLAY_CURSOR_ENV
Environment variable for replay cursor mode.
SQLITE_PATH_ENV
Environment variable for the SQLite database file path.
SYNC_ACK_ENV
Environment variable for synchronous publish ack (1 / 0).

Traits§

Actor
Re-export identity port traits and JSON stubs from photon_core. Opaque actor handle for handler execution.
IdentityFactory
Re-export identity port traits and JSON stubs from photon_core. Reconstruct handler identity from captured actor JSON (handler boundary only).
OpsLog
Structured ops metrics/events for publish, drain, DLQ, checkpoints.
PhotonBackend
Backend for publish/subscribe delivery and checkpoint persistence.
StoragePort
Storage adapter contract — append, subscribe, checkpoints, and optional retention.

Functions§

collect_admin_snapshot
Build a full admin snapshot for the given runtime (async checkpoint reads).
configure
Configure the default Photon instance used by macro-generated convenience helpers (Type::publish() / Type::subscribe()).
consumer_group_for
Stable group id alias (NATS deliver-subject analogue).
default
Clone of the process-wide Photon set by configure, if any.
durable_consumer_name
Build a Kafka-safe durable consumer group id for a keyed subscription.
fluvio_consumer_group_for
Stable group id alias (NATS deliver-subject analogue).
fluvio_durable_consumer_name
Build a Fluvio-safe durable consumer id for a keyed subscription.
fluvio_endpoint_from_env
Read Fluvio endpoint from the environment.
install_ops_log
Install the process-wide ops log (typically at server boot before Photon runtime).
kafka_brokers_from_env
Read Kafka brokers from the environment.
ops_log
Resolved ops log — NoOpsLog until install_ops_log.
resolve_photon_remote_base_url
Origin + path prefix before /api/photon (no trailing slash).
sqlite_path_from_env
Resolve database path from PATH_ENV, or a unique file under the system temp dir.

Type Aliases§

EmbeddedBackend
Back-compat alias for the default in-process mem tier GenericPhotonBackend.
Result
Result type alias for Photon operations.

Attribute Macros§

subscribe
Register an async handler (#[photon::subscribe]). Marks a function as a subscription handler registered via inventory.
topic
Register a typed topic struct (#[photon::topic]). Marks a struct as a Photon topic, generating typed publish/subscribe APIs.