Skip to content

Commit 24b3289

Browse files
refactor(sps): move to macro config (#4194)
1 parent b521df8 commit 24b3289

5 files changed

Lines changed: 110 additions & 172 deletions

File tree

.github/workspace-dep-closures.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3377,6 +3377,8 @@
33773377
"lexical_client",
33783378
"macro_auth",
33793379
"macro_aws_config",
3380+
"macro_config",
3381+
"macro_config_derive",
33803382
"macro_cors",
33813383
"macro_db_client",
33823384
"macro_entrypoint",

rust/cloud-storage/Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

rust/cloud-storage/search_processing_service/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ http-body-util = { workspace = true }
3030
lexical_client = { path = "../lexical_client" }
3131
macro_aws_config = { path = "../macro_aws_config", features = ["s3"] }
3232
macro_cors = { path = "../macro_cors" }
33+
macro_config = { path = "../macro_config" }
3334
macro_db_client = { path = "../macro_db_client", optional = true } # Make this optional
3435
macro_entrypoint = { path = "../macro_entrypoint" }
3536
macro_env = { path = "../macro_env" }

rust/cloud-storage/search_processing_service/src/config.rs

Lines changed: 86 additions & 140 deletions
Original file line numberDiff line numberDiff line change
@@ -2,29 +2,25 @@ use anyhow::Context;
22
pub use macro_env::Environment;
33
use macro_env_var::{env_vars, maybe_env_vars};
44
use macro_service_urls::LexicalServiceUrl;
5+
use secretsmanager_client::LocalOrRemoteSecret;
56

67
env_vars! {
7-
struct DatabaseUrl;
8-
struct SearchEventQueue;
9-
struct OpensearchUrl;
10-
struct OpensearchUsername;
11-
struct OpensearchPassword;
12-
struct DocumentStorageBucket;
13-
struct BackfillJobsTable;
8+
pub struct DatabaseUrl;
9+
pub struct SearchEventQueue;
10+
pub struct OpensearchUrl;
11+
pub struct OpensearchUsername;
12+
pub struct OpensearchPassword;
13+
pub struct DocumentStorageBucket;
14+
pub struct BackfillJobsTable;
1415
}
1516

1617
maybe_env_vars! {
17-
struct DatabaseUrlReadonly;
18-
struct Port;
19-
struct QueueMaxMessages;
20-
struct QueueWaitTimeSeconds;
21-
struct WorkerCount;
22-
struct BackfillCallsPageSize;
23-
struct BackfillChatsPageSize;
24-
struct BackfillChannelsPageSize;
25-
struct BackfillDocumentsPageSize;
26-
struct BackfillEmailsPageSize;
27-
struct BackfillJobTtlSeconds;
18+
pub struct BackfillCallsPageSize;
19+
pub struct BackfillChatsPageSize;
20+
pub struct BackfillChannelsPageSize;
21+
pub struct BackfillDocumentsPageSize;
22+
pub struct BackfillEmailsPageSize;
23+
pub struct BackfillJobTtlSeconds;
2824
}
2925

3026
/// Per-entity DB page sizes used by the backfill source adapters. Tunable at
@@ -43,11 +39,41 @@ const DEFAULT_CHATS_PAGE: usize = 5000;
4339
const DEFAULT_CHANNELS_PAGE: usize = 5000;
4440
const DEFAULT_DOCUMENTS_PAGE: usize = 1000;
4541
const DEFAULT_EMAILS_PAGE: usize = 1000;
42+
const DEFAULT_BACKFILL_JOB_TTL_SECONDS: u64 = 24 * 60 * 60;
4643

44+
fn parse_page_size(name: &str, raw_value: Option<&str>, default: usize) -> anyhow::Result<usize> {
45+
let page_size = raw_value
46+
.map(|raw| {
47+
raw.parse::<usize>()
48+
.with_context(|| format!("{name} must be a positive integer"))
49+
})
50+
.transpose()?
51+
.unwrap_or(default);
52+
53+
if page_size == 0 {
54+
anyhow::bail!("{name} must be > 0");
55+
}
56+
57+
Ok(page_size)
58+
}
59+
60+
fn parse_u64(name: &str, raw_value: Option<&str>, default: u64) -> anyhow::Result<u64> {
61+
raw_value
62+
.map(|raw| {
63+
raw.parse::<u64>()
64+
.with_context(|| format!("{name} must be a positive integer"))
65+
})
66+
.transpose()
67+
.map(|value| value.unwrap_or(default))
68+
}
69+
70+
/// The configuration parameters for the application.
71+
#[derive(macro_config::MacroConfig)]
72+
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
4773
pub struct Config {
4874
/// The connection URL for the Postgres database this application should use.
4975
/// For deployed applications, this is a secret stored in AWS Secrets Manager.
50-
pub database_url: String,
76+
pub database_url: LocalOrRemoteSecret<DatabaseUrl>,
5177

5278
/// Optional connection URL (or SM secret id when `environment != Local`)
5379
/// for the macrodb read-replica. When present, backfill reads run against
@@ -58,181 +84,101 @@ pub struct Config {
5884
pub database_url_readonly: Option<String>,
5985

6086
/// The port to listen for HTTP requests on.
87+
#[macro_config_default(8080)]
6188
pub port: usize,
6289

6390
/// The search text extractor queue
64-
pub search_event_queue: String,
91+
pub search_event_queue: SearchEventQueue,
6592
/// The queue max messages per poll
93+
#[macro_config_default(10)]
6694
pub queue_max_messages: i32,
6795
/// The queue wait time seconds
96+
#[macro_config_default(20)]
6897
pub queue_wait_time_seconds: i32,
6998

7099
/// The environment we are in
100+
#[macro_config_default(Environment::new_or_prod())]
71101
pub environment: Environment,
72102

73103
/// The URL for the Opensearch instance
74-
pub opensearch_url: String,
104+
pub opensearch_url: OpensearchUrl,
75105
/// The username for the Opensearch instance
76-
pub opensearch_username: String,
106+
pub opensearch_username: OpensearchUsername,
77107
/// The password for the Opensearch instance
78-
pub opensearch_password: String,
108+
pub opensearch_password: LocalOrRemoteSecret<OpensearchPassword>,
79109

80110
/// The bucket where documents are stored
81-
pub document_storage_bucket: String,
111+
pub document_storage_bucket: DocumentStorageBucket,
82112

83113
/// The number of workers to spawn
114+
#[macro_config_default(10)]
84115
pub worker_count: u8,
85116

86117
/// The URL for the Lexical service
118+
#[macro_config_default(LexicalServiceUrl::unwrap_new().to_string())]
87119
pub lexical_service_url: String,
88120

89-
/// Per-entity DB page sizes for backfill adapters.
90-
pub backfill_page_sizes: BackfillPageSizes,
121+
/// DB page size used when backfilling call records.
122+
pub backfill_calls_page_size: BackfillCallsPageSize,
123+
/// DB page size used when backfilling chats.
124+
pub backfill_chats_page_size: BackfillChatsPageSize,
125+
/// DB page size used when backfilling channels.
126+
pub backfill_channels_page_size: BackfillChannelsPageSize,
127+
/// DB page size used when backfilling documents.
128+
pub backfill_documents_page_size: BackfillDocumentsPageSize,
129+
/// DB page size used when backfilling emails.
130+
pub backfill_emails_page_size: BackfillEmailsPageSize,
91131

92132
/// DynamoDB table name backing the backfill job registry. Items carry an
93133
/// `expires_at` epoch attribute that DynamoDB's TTL sweeps in the
94134
/// background, so completed jobs vanish on their own.
95-
pub backfill_jobs_table: String,
135+
pub backfill_jobs_table: BackfillJobsTable,
96136

97137
/// TTL applied to the `expires_at` attribute on each job record. Acts as
98138
/// the GC mechanism — DynamoDB removes items shortly after this elapses.
99-
pub backfill_job_ttl_seconds: u64,
100-
}
101-
102-
fn parse_page_size(name: &str, raw_value: Option<String>, default: usize) -> anyhow::Result<usize> {
103-
match raw_value {
104-
Some(raw) => raw
105-
.parse::<usize>()
106-
.with_context(|| format!("{name} must be a positive integer"))
107-
.and_then(|n| {
108-
if n == 0 {
109-
anyhow::bail!("{name} must be > 0");
110-
}
111-
Ok(n)
112-
}),
113-
None => Ok(default),
114-
}
139+
pub backfill_job_ttl_seconds: BackfillJobTtlSeconds,
115140
}
116141

117142
impl Config {
118143
pub fn from_env() -> anyhow::Result<Self> {
119-
let database_url = DatabaseUrl::new()
120-
.context("DATABASE_URL must be provided")?
121-
.to_string();
122-
123-
let database_url_readonly = DatabaseUrlReadonly::new().map(|url| url.to_string());
124-
125-
let port = Port::new()
126-
.map(|port| port.parse::<usize>().context("should be valid port number"))
127-
.transpose()?
128-
.unwrap_or(8080);
129-
130-
let environment = Environment::new_or_prod();
131-
132-
let search_event_queue = SearchEventQueue::new()
133-
.context("SEARCH_EVENT_QUEUE must be provided")?
134-
.to_string();
135-
136-
let queue_max_messages = QueueMaxMessages::new()
137-
.map(|queue_max_messages| {
138-
queue_max_messages
139-
.parse::<i32>()
140-
.context("QUEUE_MAX_MESSAGES must be a valid i32")
141-
})
142-
.transpose()?
143-
.unwrap_or(10);
144-
145-
let queue_wait_time_seconds = QueueWaitTimeSeconds::new()
146-
.map(|queue_wait_time_seconds| {
147-
queue_wait_time_seconds
148-
.parse::<i32>()
149-
.context("QUEUE_WAIT_TIME_SECONDS must be a valid i32")
150-
})
151-
.transpose()?
152-
.unwrap_or(20);
153-
154-
let opensearch_url = OpensearchUrl::new()
155-
.context("OPENSEARCH_URL must be provided")?
156-
.to_string();
157-
let opensearch_username = OpensearchUsername::new()
158-
.context("OPENSEARCH_USERNAME must be provided")?
159-
.to_string();
160-
let opensearch_password = OpensearchPassword::new()
161-
.context("OPENSEARCH_PASSWORD must be provided")?
162-
.to_string();
163-
164-
let document_storage_bucket = DocumentStorageBucket::new()
165-
.context("DOCUMENT_STORAGE_BUCKET must be provided")?
166-
.to_string();
167-
168-
let worker_count = WorkerCount::new()
169-
.map(|worker_count| {
170-
worker_count
171-
.parse::<u8>()
172-
.context("WORKER_COUNT must be a valid u8")
173-
})
174-
.transpose()?
175-
.unwrap_or(10);
176-
177-
let lexical_service_url = LexicalServiceUrl::new()?.to_string();
178-
179-
let backfill_page_sizes = BackfillPageSizes {
144+
macro_config::ConfigLoader::load::<Config>().context("failed to load config")
145+
}
146+
147+
pub fn backfill_page_sizes(&self) -> anyhow::Result<BackfillPageSizes> {
148+
Ok(BackfillPageSizes {
180149
calls: parse_page_size(
181150
"BACKFILL_CALLS_PAGE_SIZE",
182-
BackfillCallsPageSize::new().map(|value| value.to_string()),
151+
self.backfill_calls_page_size.value(),
183152
DEFAULT_CALLS_PAGE,
184153
)?,
185154
chats: parse_page_size(
186155
"BACKFILL_CHATS_PAGE_SIZE",
187-
BackfillChatsPageSize::new().map(|value| value.to_string()),
156+
self.backfill_chats_page_size.value(),
188157
DEFAULT_CHATS_PAGE,
189158
)?,
190159
channels: parse_page_size(
191160
"BACKFILL_CHANNELS_PAGE_SIZE",
192-
BackfillChannelsPageSize::new().map(|value| value.to_string()),
161+
self.backfill_channels_page_size.value(),
193162
DEFAULT_CHANNELS_PAGE,
194163
)?,
195164
documents: parse_page_size(
196165
"BACKFILL_DOCUMENTS_PAGE_SIZE",
197-
BackfillDocumentsPageSize::new().map(|value| value.to_string()),
166+
self.backfill_documents_page_size.value(),
198167
DEFAULT_DOCUMENTS_PAGE,
199168
)?,
200169
emails: parse_page_size(
201170
"BACKFILL_EMAILS_PAGE_SIZE",
202-
BackfillEmailsPageSize::new().map(|value| value.to_string()),
171+
self.backfill_emails_page_size.value(),
203172
DEFAULT_EMAILS_PAGE,
204173
)?,
205-
};
206-
207-
let backfill_jobs_table = BackfillJobsTable::new()
208-
.context("BACKFILL_JOBS_TABLE must be provided")?
209-
.to_string();
210-
let backfill_job_ttl_seconds = BackfillJobTtlSeconds::new()
211-
.map(|backfill_job_ttl_seconds| {
212-
backfill_job_ttl_seconds
213-
.parse::<u64>()
214-
.context("BACKFILL_JOB_TTL_SECONDS must be a positive integer")
215-
})
216-
.transpose()?
217-
.unwrap_or(24 * 60 * 60);
218-
219-
Ok(Config {
220-
database_url,
221-
database_url_readonly,
222-
port,
223-
search_event_queue,
224-
queue_max_messages,
225-
queue_wait_time_seconds,
226-
environment,
227-
opensearch_url,
228-
opensearch_username,
229-
opensearch_password,
230-
document_storage_bucket,
231-
worker_count,
232-
lexical_service_url,
233-
backfill_page_sizes,
234-
backfill_jobs_table,
235-
backfill_job_ttl_seconds,
236174
})
237175
}
176+
177+
pub fn backfill_job_ttl_seconds(&self) -> anyhow::Result<u64> {
178+
parse_u64(
179+
"BACKFILL_JOB_TTL_SECONDS",
180+
self.backfill_job_ttl_seconds.value(),
181+
DEFAULT_BACKFILL_JOB_TTL_SECONDS,
182+
)
183+
}
238184
}

0 commit comments

Comments
 (0)