Skip to content

Commit dd824dd

Browse files
committed
extract fastly cdn integration into subcrate
1 parent 5044708 commit dd824dd

File tree

18 files changed

+632
-460
lines changed

18 files changed

+632
-460
lines changed

Cargo.lock

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

Cargo.toml

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,18 +22,20 @@ exclude = [
2222

2323
[workspace.dependencies]
2424
anyhow = { version = "1.0.42", features = ["backtrace"]}
25-
axum-extra = { version = "0.12.0", features = ["typed-header", "routing", "middleware"] }
2625
askama = "0.14.0"
26+
axum-extra = { version = "0.12.0", features = ["typed-header", "routing", "middleware"] }
2727
bincode = "2.0.1"
2828
chrono = { version = "0.4.11", default-features = false, features = ["clock", "serde"] }
2929
derive_more = { version = "2.0.0", features = ["display", "deref", "from", "into", "from_str"] }
3030
http = "1.0.0"
3131
itertools = { version = "0.14.0" }
32+
mockito = "1.0.2"
3233
opentelemetry = "0.31.0"
3334
opentelemetry-otlp = { version = "0.31.0", features = ["grpc-tonic", "metrics"] }
3435
opentelemetry-resource-detectors = "0.10.0"
3536
opentelemetry_sdk = { version = "0.31.0", features = ["rt-tokio"] }
3637
regex = "1"
38+
reqwest = { version = "0.12", features = ["json", "gzip"] }
3739
sentry = { version = "0.46.0", features = ["panic", "tracing", "tower-http", "anyhow", "backtrace"] }
3840
serde = { version = "1.0", features = ["derive"] }
3941
serde_json = "1.0"
@@ -44,6 +46,7 @@ tracing = "0.1.37"
4446
url = { version = "2.1.1", features = ["serde"] }
4547

4648
[dependencies]
49+
docs_rs_fastly = { path = "crates/lib/docs_rs_fastly" }
4750
docs_rs_env_vars = { path = "crates/lib/docs_rs_env_vars" }
4851
docs_rs_headers = { path = "crates/lib/docs_rs_headers" }
4952
docs_rs_logging = { path = "crates/lib/docs_rs_logging" }
@@ -62,7 +65,7 @@ crates-index = { version = "3.0.0", default-features = false, features = ["git",
6265
rayon = "1.6.1"
6366
num_cpus = "1.15.0"
6467
crates-index-diff = { version = "28.0.0", features = [ "max-performance" ]}
65-
reqwest = { version = "0.12", features = ["json", "gzip"] }
68+
reqwest = { workspace = true }
6669
slug = "0.1.1"
6770
sqlx = { workspace = true }
6871
url = { workspace = true }
@@ -134,14 +137,15 @@ chrono = { workspace = true }
134137
constant_time_eq = "0.4.2"
135138

136139
[dev-dependencies]
140+
docs_rs_fastly = { path = "crates/lib/docs_rs_fastly", features = ["testing"] }
137141
docs_rs_headers = { path = "crates/lib/docs_rs_headers", features = ["testing"] }
138142
docs_rs_opentelemetry = { path = "crates/lib/docs_rs_opentelemetry", features = ["testing"] }
139143
docs_rs_types = { path = "crates/lib/docs_rs_types", features = ["testing"] }
140144
criterion = "0.8.0"
141145
kuchikiki = "0.8"
142146
http-body-util = "0.1.0"
143147
rand = "0.9"
144-
mockito = "1.0.2"
148+
mockito = { workspace = true }
145149
test-case = { workspace = true }
146150
tower = { version = "0.5.1", features = ["util"] }
147151
opentelemetry_sdk = { version = "0.31.0", features = ["rt-tokio", "testing"] }
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
[package]
2+
name = "docs_rs_fastly"
3+
version = "0.1.0"
4+
edition = "2024"
5+
6+
[dependencies]
7+
anyhow = { workspace = true }
8+
chrono = { workspace = true }
9+
docs_rs_types = { path = "../docs_rs_types" }
10+
docs_rs_env_vars = { path = "../docs_rs_env_vars" }
11+
docs_rs_headers = { path = "../docs_rs_headers" }
12+
docs_rs_opentelemetry = { path = "../docs_rs_opentelemetry" }
13+
docs_rs_utils = { path = "../docs_rs_utils" }
14+
http = { workspace = true }
15+
itertools = { workspace = true }
16+
opentelemetry = { workspace = true }
17+
reqwest = { workspace = true }
18+
tracing = { workspace = true }
19+
url = { workspace = true }
20+
tokio = { workspace = true, optional = true }
21+
22+
[dev-dependencies]
23+
docs_rs_headers = { path = "../docs_rs_headers", features = ["testing"] }
24+
docs_rs_opentelemetry = { path = "../docs_rs_opentelemetry", features = ["testing"] }
25+
mockito = { workspace = true }
26+
tokio = { workspace = true }
27+
28+
[features]
29+
testing = ["dep:tokio"]
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
use crate::CdnBehaviour;
2+
use anyhow::Result;
3+
use docs_rs_headers::{SurrogateKey, SurrogateKeys};
4+
use tokio::sync::Mutex;
5+
6+
#[derive(Debug, Default)]
7+
pub struct MockCdn {
8+
pub purged: Mutex<SurrogateKeys>,
9+
}
10+
11+
impl CdnBehaviour for MockCdn {
12+
async fn purge_surrogate_keys<I>(&self, keys: I) -> Result<()>
13+
where
14+
I: IntoIterator<Item = SurrogateKey> + 'static + Send,
15+
I::IntoIter: Send,
16+
{
17+
let mut purged = self.purged.lock().await;
18+
purged.try_extend(keys)?;
19+
Ok(())
20+
}
21+
}
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
#[cfg(feature = "testing")]
2+
pub mod mock;
3+
pub mod real;
4+
5+
use crate::Config;
6+
use anyhow::Result;
7+
use docs_rs_headers::SurrogateKey;
8+
use docs_rs_opentelemetry::AnyMeterProvider;
9+
use docs_rs_types::KrateName;
10+
use std::iter;
11+
12+
pub trait CdnBehaviour {
13+
fn purge_surrogate_keys<I>(&self, keys: I) -> impl Future<Output = Result<()>> + Send
14+
where
15+
I: IntoIterator<Item = SurrogateKey> + 'static + Send,
16+
I::IntoIter: Send;
17+
18+
fn queue_crate_invalidation(
19+
&self,
20+
krate_name: &KrateName,
21+
) -> impl Future<Output = Result<()>> + Send {
22+
self.purge_surrogate_keys(iter::once(SurrogateKey::from(krate_name.clone())))
23+
}
24+
}
25+
26+
#[derive(Debug)]
27+
pub enum Cdn {
28+
Real(real::RealCdn),
29+
#[cfg(feature = "testing")]
30+
Mock(mock::MockCdn),
31+
}
32+
33+
/// normal functionality
34+
impl Cdn {
35+
pub fn from_config(config: &Config, meter_provider: &AnyMeterProvider) -> Result<Self> {
36+
Ok(Self::Real(real::RealCdn::from_config(
37+
config,
38+
meter_provider,
39+
)?))
40+
}
41+
}
42+
43+
/// testing functionality
44+
#[cfg(feature = "testing")]
45+
impl Cdn {
46+
pub fn mock() -> Self {
47+
Self::Mock(mock::MockCdn::default())
48+
}
49+
50+
pub async fn purged_keys(&self) -> Result<docs_rs_headers::SurrogateKeys> {
51+
let Self::Mock(cdn) = self else {
52+
anyhow::bail!("found real cdn, no collected purges");
53+
};
54+
55+
let purges = cdn.purged.lock().await;
56+
Ok(purges.clone())
57+
}
58+
}
59+
60+
impl CdnBehaviour for Cdn {
61+
async fn purge_surrogate_keys<I>(&self, keys: I) -> Result<()>
62+
where
63+
I: IntoIterator<Item = SurrogateKey> + 'static + Send,
64+
I::IntoIter: Send,
65+
{
66+
match self {
67+
Self::Real(real) => real.purge_surrogate_keys(keys).await,
68+
#[cfg(feature = "testing")]
69+
Self::Mock(mock) => mock.purge_surrogate_keys(keys).await,
70+
}
71+
}
72+
}

0 commit comments

Comments
 (0)