Skip to main content

photon_backend/models/
subscribe_opts.rs

1//! Options and handle for typed subscribe.
2
3use super::SubscriptionMode;
4
5/// Options specific to consumer-group subscriptions.
6///
7/// Used with [`SubscribeOpts::consumer_group`]. Checkpoints are owned by `group_id` × shard,
8/// not per-instance subscription names.
9#[derive(Debug, Clone)]
10pub struct GroupOpts {
11    /// Stable consumer group identifier (shared across replicas).
12    pub group_id: String,
13    /// Override virtual shard count (defaults to topic `#[photon::topic(shards = ...)]`).
14    pub shard_count: Option<u32>,
15    /// Fleet member id for lease coordination (static env assignment when unset).
16    pub instance_id: Option<String>,
17}
18
19impl GroupOpts {
20    /// Create group options with the given `group_id`.
21    pub fn new(group_id: impl Into<String>) -> Self {
22        Self {
23            group_id: group_id.into(),
24            shard_count: None,
25            instance_id: None,
26        }
27    }
28
29    /// Override virtual shard count for this subscription.
30    #[must_use]
31    pub const fn shards(mut self, count: u32) -> Self {
32        self.shard_count = Some(count);
33        self
34    }
35
36    /// Set fleet member instance id for lease-based assignment.
37    #[must_use]
38    pub fn instance_id(mut self, id: impl Into<String>) -> Self {
39        self.instance_id = Some(id.into());
40        self
41    }
42}
43
44/// Options for subscribing to a topic.
45///
46/// Pass to the typed API from [`topic`](https://docs.rs/uf-photon/latest/photon/attr.topic.html):
47/// `EventType::subscribe_on(&photon, opts)`.
48///
49/// Runnable: `keyed_topic`, `consumer_group`. Getting started:
50/// [publish and subscribe](https://docs.rs/uf-photon/latest/photon/#4-publish-and-subscribe).
51///
52/// # Examples
53///
54/// Ephemeral stream with partition filter (see `keyed_topic` example):
55///
56/// ```rust,ignore
57/// use futures::StreamExt;
58/// use photon::{SubscribeOpts, topic};
59///
60/// #[topic(name = "examples.orders", keyed_by = "customer_id")]
61/// struct OrderPlaced { customer_id: String, amount_cents: u64 }
62///
63/// # async fn demo(photon: &photon::Photon) -> photon::Result<()> {
64/// let opts = SubscribeOpts::default_ephemeral().topic_key_filter("alice");
65/// let mut stream = OrderPlaced::subscribe_on(photon, opts).await?;
66/// let _ = stream.next().await;
67/// # Ok(())
68/// # }
69/// ```
70///
71/// Durable broadcast by subscription name:
72///
73/// ```rust,no_run
74/// use photon_backend::SubscribeOpts;
75///
76/// let opts = SubscribeOpts::broadcast().subscription_name("my-worker");
77/// ```
78#[derive(Debug, Clone, Default)]
79pub struct SubscribeOpts {
80    /// Subscription name (required for durable broadcast mode).
81    pub subscription_name: Option<String>,
82    /// Filter by topic key (for keyed topics).
83    pub topic_key_filter: Option<String>,
84    /// Durable or ephemeral mode.
85    pub mode: SubscriptionMode,
86    /// Consumer group (load-balanced); mutually exclusive with durable subscription name.
87    pub consumer_group: Option<GroupOpts>,
88}
89
90impl SubscribeOpts {
91    /// Create default options (ephemeral, no key filter).
92    #[must_use]
93    pub const fn default_ephemeral() -> Self {
94        Self {
95            subscription_name: None,
96            topic_key_filter: None,
97            mode: SubscriptionMode::Ephemeral,
98            consumer_group: None,
99        }
100    }
101
102    /// Broadcast durable subscription (today's default).
103    #[must_use]
104    pub fn broadcast() -> Self {
105        Self {
106            mode: SubscriptionMode::Durable,
107            ..Self::default_ephemeral()
108        }
109    }
110
111    /// Load-balanced consumer group subscription.
112    #[must_use]
113    pub fn consumer_group(mut self, opts: GroupOpts) -> Self {
114        self.subscription_name = None;
115        self.topic_key_filter = None;
116        self.mode = SubscriptionMode::Durable;
117        self.consumer_group = Some(opts);
118        self
119    }
120
121    /// Set subscription name (for durable mode).
122    #[must_use]
123    pub fn subscription_name(mut self, name: impl Into<String>) -> Self {
124        self.subscription_name = Some(name.into());
125        self
126    }
127
128    /// Set topic key filter.
129    #[must_use]
130    pub fn topic_key_filter(mut self, key: impl Into<String>) -> Self {
131        self.topic_key_filter = Some(key.into());
132        self
133    }
134
135    /// Set mode.
136    #[must_use]
137    pub const fn mode(mut self, mode: SubscriptionMode) -> Self {
138        self.mode = mode;
139        self
140    }
141}
142
143/// Placeholder for future subscription lifecycle control (cancel, pause).
144///
145/// v0.1 returns a no-op handle; dropping the subscribe stream task is the supported way to
146/// stop an ephemeral subscription today.
147#[derive(Debug, Default)]
148pub struct SubscriptionHandle {
149    _private: (),
150}
151
152impl SubscriptionHandle {
153    /// Create a new handle (reserved for future cancel/pause APIs).
154    #[must_use]
155    pub const fn new() -> Self {
156        Self { _private: () }
157    }
158}