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/// # Examples
47///
48/// Ephemeral stream with partition filter (see `keyed_topic` example):
49///
50/// ```rust,no_run
51/// use photon_backend::SubscribeOpts;
52///
53/// # async fn demo() -> photon_backend::Result<()> {
54/// let opts = SubscribeOpts::default_ephemeral().topic_key_filter("alice");
55/// # Ok(())
56/// # }
57/// ```
58///
59/// Durable broadcast by subscription name:
60///
61/// ```rust,no_run
62/// use photon_backend::SubscribeOpts;
63///
64/// let opts = SubscribeOpts::broadcast().subscription_name("my-worker");
65/// ```
66#[derive(Debug, Clone, Default)]
67pub struct SubscribeOpts {
68    /// Subscription name (required for durable broadcast mode).
69    pub subscription_name: Option<String>,
70    /// Filter by topic key (for keyed topics).
71    pub topic_key_filter: Option<String>,
72    /// Durable or ephemeral mode.
73    pub mode: SubscriptionMode,
74    /// Consumer group (load-balanced); mutually exclusive with durable subscription name.
75    pub consumer_group: Option<GroupOpts>,
76}
77
78impl SubscribeOpts {
79    /// Create default options (ephemeral, no key filter).
80    #[must_use]
81    pub const fn default_ephemeral() -> Self {
82        Self {
83            subscription_name: None,
84            topic_key_filter: None,
85            mode: SubscriptionMode::Ephemeral,
86            consumer_group: None,
87        }
88    }
89
90    /// Broadcast durable subscription (today's default).
91    #[must_use]
92    pub fn broadcast() -> Self {
93        Self {
94            mode: SubscriptionMode::Durable,
95            ..Self::default_ephemeral()
96        }
97    }
98
99    /// Load-balanced consumer group subscription.
100    #[must_use]
101    pub fn consumer_group(mut self, opts: GroupOpts) -> Self {
102        self.subscription_name = None;
103        self.topic_key_filter = None;
104        self.mode = SubscriptionMode::Durable;
105        self.consumer_group = Some(opts);
106        self
107    }
108
109    /// Set subscription name (for durable mode).
110    #[must_use]
111    pub fn subscription_name(mut self, name: impl Into<String>) -> Self {
112        self.subscription_name = Some(name.into());
113        self
114    }
115
116    /// Set topic key filter.
117    #[must_use]
118    pub fn topic_key_filter(mut self, key: impl Into<String>) -> Self {
119        self.topic_key_filter = Some(key.into());
120        self
121    }
122
123    /// Set mode.
124    #[must_use]
125    pub const fn mode(mut self, mode: SubscriptionMode) -> Self {
126        self.mode = mode;
127        self
128    }
129}
130
131/// Placeholder for future subscription lifecycle control (cancel, pause).
132///
133/// v0.1 returns a no-op handle; dropping the subscribe stream task is the supported way to
134/// stop an ephemeral subscription today.
135#[derive(Debug, Default)]
136pub struct SubscriptionHandle {
137    _private: (),
138}
139
140impl SubscriptionHandle {
141    /// Create a new handle (reserved for future cancel/pause APIs).
142    #[must_use]
143    pub const fn new() -> Self {
144        Self { _private: () }
145    }
146}