forked from cadey/xesite
move poking services into app boot after systemd notify
Signed-off-by: Christine Dodrill <me@christine.website>
This commit is contained in:
parent
17af42bc69
commit
4bcc848bb1
|
@ -212,6 +212,21 @@ version = "1.0.66"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4c0496836a84f8d0495758516b8621a622beb77c0fed418570e50764093ced48"
|
checksum = "4c0496836a84f8d0495758516b8621a622beb77c0fed418570e50764093ced48"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cfcache"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"eyre",
|
||||||
|
"kankyo",
|
||||||
|
"reqwest",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
"thiserror",
|
||||||
|
"tokio",
|
||||||
|
"tracing",
|
||||||
|
"tracing-futures",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cfg-if"
|
name = "cfg-if"
|
||||||
version = "0.1.10"
|
version = "0.1.10"
|
||||||
|
@ -1068,12 +1083,35 @@ dependencies = [
|
||||||
"kernel32-sys",
|
"kernel32-sys",
|
||||||
"libc",
|
"libc",
|
||||||
"log",
|
"log",
|
||||||
"miow",
|
"miow 0.2.2",
|
||||||
"net2",
|
"net2",
|
||||||
"slab",
|
"slab",
|
||||||
"winapi 0.2.8",
|
"winapi 0.2.8",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "mio-named-pipes"
|
||||||
|
version = "0.1.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0840c1c50fd55e521b247f949c241c9997709f23bd7f023b9762cd561e935656"
|
||||||
|
dependencies = [
|
||||||
|
"log",
|
||||||
|
"mio",
|
||||||
|
"miow 0.3.6",
|
||||||
|
"winapi 0.3.9",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "mio-uds"
|
||||||
|
version = "0.6.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "afcb699eb26d4332647cc848492bbc15eafb26f08d0304550d5aa1f612e066f0"
|
||||||
|
dependencies = [
|
||||||
|
"iovec",
|
||||||
|
"libc",
|
||||||
|
"mio",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "miow"
|
name = "miow"
|
||||||
version = "0.2.2"
|
version = "0.2.2"
|
||||||
|
@ -1086,6 +1124,16 @@ dependencies = [
|
||||||
"ws2_32-sys",
|
"ws2_32-sys",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "miow"
|
||||||
|
version = "0.3.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5a33c1b55807fbed163481b5ba66db4b2fa6cde694a5027be10fb724206c5897"
|
||||||
|
dependencies = [
|
||||||
|
"socket2",
|
||||||
|
"winapi 0.3.9",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "multipart"
|
name = "multipart"
|
||||||
version = "0.17.1"
|
version = "0.17.1"
|
||||||
|
@ -1913,6 +1961,15 @@ version = "1.0.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b6fa3938c99da4914afedd13bf3d79bcb6c277d1b2c398d23257a304d9e1b074"
|
checksum = "b6fa3938c99da4914afedd13bf3d79bcb6c277d1b2c398d23257a304d9e1b074"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "signal-hook-registry"
|
||||||
|
version = "1.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "16f1d0fef1604ba8f7a073c7e701f213e056707210e9020af4528e0101ce11a6"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sitemap"
|
name = "sitemap"
|
||||||
version = "0.4.1"
|
version = "0.4.1"
|
||||||
|
@ -2069,12 +2126,17 @@ dependencies = [
|
||||||
"futures-core",
|
"futures-core",
|
||||||
"iovec",
|
"iovec",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
|
"libc",
|
||||||
"memchr",
|
"memchr",
|
||||||
"mio",
|
"mio",
|
||||||
|
"mio-named-pipes",
|
||||||
|
"mio-uds",
|
||||||
"num_cpus",
|
"num_cpus",
|
||||||
"pin-project-lite 0.1.11",
|
"pin-project-lite 0.1.11",
|
||||||
|
"signal-hook-registry",
|
||||||
"slab",
|
"slab",
|
||||||
"tokio-macros",
|
"tokio-macros",
|
||||||
|
"winapi 0.3.9",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -2603,6 +2665,7 @@ checksum = "d089681aa106a86fade1b0128fb5daf07d5867a509ab036d99988dec80429a57"
|
||||||
name = "xesite"
|
name = "xesite"
|
||||||
version = "2.2.0"
|
version = "2.2.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"cfcache",
|
||||||
"chrono",
|
"chrono",
|
||||||
"color-eyre",
|
"color-eyre",
|
||||||
"comrak",
|
"comrak",
|
||||||
|
@ -2621,7 +2684,7 @@ dependencies = [
|
||||||
"pfacts",
|
"pfacts",
|
||||||
"pretty_env_logger",
|
"pretty_env_logger",
|
||||||
"prometheus",
|
"prometheus",
|
||||||
"rand 0.7.3",
|
"rand 0.8.1",
|
||||||
"reqwest",
|
"reqwest",
|
||||||
"ructe",
|
"ructe",
|
||||||
"sdnotify",
|
"sdnotify",
|
||||||
|
|
|
@ -21,6 +21,7 @@ log = "0.4"
|
||||||
mime = "0.3.0"
|
mime = "0.3.0"
|
||||||
prometheus = { version = "0.10", default-features = false, features = ["process"] }
|
prometheus = { version = "0.10", default-features = false, features = ["process"] }
|
||||||
rand = "0"
|
rand = "0"
|
||||||
|
reqwest = { version = "0.10", features = ["json"] }
|
||||||
sdnotify = { version = "0.1", default-features = false }
|
sdnotify = { version = "0.1", default-features = false }
|
||||||
serde_dhall = "0.8.0"
|
serde_dhall = "0.8.0"
|
||||||
serde = { version = "1", features = ["derive"] }
|
serde = { version = "1", features = ["derive"] }
|
||||||
|
@ -37,6 +38,7 @@ url = "2"
|
||||||
uuid = { version = "0.8", features = ["serde", "v4"] }
|
uuid = { version = "0.8", features = ["serde", "v4"] }
|
||||||
|
|
||||||
# workspace dependencies
|
# workspace dependencies
|
||||||
|
cfcache = { path = "./lib/cfcache" }
|
||||||
go_vanity = { path = "./lib/go_vanity" }
|
go_vanity = { path = "./lib/go_vanity" }
|
||||||
jsonfeed = { path = "./lib/jsonfeed" }
|
jsonfeed = { path = "./lib/jsonfeed" }
|
||||||
mi = { path = "./lib/mi" }
|
mi = { path = "./lib/mi" }
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
[package]
|
||||||
|
name = "cfcache"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["Christine Dodrill <me@christine.website>"]
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
reqwest = { version = "0.10", features = ["json"] }
|
||||||
|
serde_json = "1.0"
|
||||||
|
serde = { version = "1", features = ["derive"] }
|
||||||
|
thiserror = "1"
|
||||||
|
tracing = "0.1"
|
||||||
|
tracing-futures = "0.2"
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
eyre = "0.6.5"
|
||||||
|
kankyo = "0.3"
|
||||||
|
tokio = { version = "0.2", features = ["full"] }
|
|
@ -0,0 +1,15 @@
|
||||||
|
use eyre::Result;
|
||||||
|
|
||||||
|
#[tokio::main]
|
||||||
|
async fn main() -> Result<()> {
|
||||||
|
kankyo::init()?;
|
||||||
|
|
||||||
|
let key = std::env::var("CF_TOKEN")?;
|
||||||
|
let zone_id = std::env::var("CF_ZONE_ID")?;
|
||||||
|
|
||||||
|
let cli = cfcache::Client::new(key, zone_id)?;
|
||||||
|
cli.purge(vec!["https://christine.website/.within/health".to_string()])
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
|
@ -0,0 +1,64 @@
|
||||||
|
use reqwest::header;
|
||||||
|
use tracing::instrument;
|
||||||
|
|
||||||
|
pub type Result<T = ()> = std::result::Result<T, Error>;
|
||||||
|
|
||||||
|
#[derive(thiserror::Error, Debug)]
|
||||||
|
pub enum Error {
|
||||||
|
#[error("json error: {0}")]
|
||||||
|
Json(#[from] serde_json::Error),
|
||||||
|
|
||||||
|
#[error("request error: {0}")]
|
||||||
|
Request(#[from] reqwest::Error),
|
||||||
|
|
||||||
|
#[error("invalid header value: {0}")]
|
||||||
|
InvalidHeaderValue(#[from] reqwest::header::InvalidHeaderValue),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Client {
|
||||||
|
zone_id: String,
|
||||||
|
cli: reqwest::Client,
|
||||||
|
}
|
||||||
|
|
||||||
|
static USER_AGENT: &str = concat!(
|
||||||
|
"xesite ",
|
||||||
|
env!("CARGO_PKG_NAME"),
|
||||||
|
"/",
|
||||||
|
env!("CARGO_PKG_VERSION")
|
||||||
|
);
|
||||||
|
|
||||||
|
impl Client {
|
||||||
|
pub fn new(api_key: String, zone_id: String) -> Result<Self> {
|
||||||
|
let mut headers = header::HeaderMap::new();
|
||||||
|
headers.insert(
|
||||||
|
header::AUTHORIZATION,
|
||||||
|
header::HeaderValue::from_str(&format!("Bearer {}", api_key))?,
|
||||||
|
);
|
||||||
|
|
||||||
|
let cli = reqwest::Client::builder()
|
||||||
|
.user_agent(USER_AGENT)
|
||||||
|
.default_headers(headers)
|
||||||
|
.build()?;
|
||||||
|
|
||||||
|
Ok(Self { zone_id, cli })
|
||||||
|
}
|
||||||
|
|
||||||
|
#[instrument(skip(self), err)]
|
||||||
|
pub async fn purge(&self, urls: Vec<String>) -> Result {
|
||||||
|
#[derive(serde::Serialize)]
|
||||||
|
struct Files {
|
||||||
|
files: Vec<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
self.cli
|
||||||
|
.post(&format!(
|
||||||
|
"https://api.cloudflare.com/client/v4/zones/{}/purge_cache",
|
||||||
|
self.zone_id
|
||||||
|
))
|
||||||
|
.json(&Files { files: urls })
|
||||||
|
.send()
|
||||||
|
.await?
|
||||||
|
.error_for_status()?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
|
@ -34,7 +34,7 @@ impl Client {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[instrument(skip(self))]
|
#[instrument(skip(self), err)]
|
||||||
pub async fn mentioners(&self, url: String) -> Result<Vec<WebMention>> {
|
pub async fn mentioners(&self, url: String) -> Result<Vec<WebMention>> {
|
||||||
Ok(self
|
Ok(self
|
||||||
.cli
|
.cli
|
||||||
|
@ -46,6 +46,16 @@ impl Client {
|
||||||
.json()
|
.json()
|
||||||
.await?)
|
.await?)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[instrument(skip(self), err)]
|
||||||
|
pub async fn refresh(&self) -> Result<()> {
|
||||||
|
self.cli
|
||||||
|
.post("https://mi.within.website/api/blog/refresh")
|
||||||
|
.send()
|
||||||
|
.await?
|
||||||
|
.error_for_status()?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, Eq, PartialEq, Clone)]
|
#[derive(Debug, Deserialize, Eq, PartialEq, Clone)]
|
||||||
|
|
|
@ -5,6 +5,7 @@ use std::{fs, path::PathBuf};
|
||||||
use tracing::{error, instrument};
|
use tracing::{error, instrument};
|
||||||
|
|
||||||
pub mod markdown;
|
pub mod markdown;
|
||||||
|
pub mod poke;
|
||||||
|
|
||||||
#[derive(Clone, Deserialize)]
|
#[derive(Clone, Deserialize)]
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
|
|
|
@ -0,0 +1,86 @@
|
||||||
|
use color_eyre::eyre::Result;
|
||||||
|
use std::{env, time::Duration};
|
||||||
|
use tokio::time::delay_for;
|
||||||
|
|
||||||
|
#[instrument(err)]
|
||||||
|
pub async fn the_cloud() -> Result<()> {
|
||||||
|
info!("waiting for things to settle");
|
||||||
|
delay_for(Duration::from_secs(10)).await;
|
||||||
|
|
||||||
|
info!("purging cloudflare cache");
|
||||||
|
cloudflare().await?;
|
||||||
|
|
||||||
|
info!("waiting for the cloudflare cache to purge globally");
|
||||||
|
delay_for(Duration::from_secs(45)).await;
|
||||||
|
|
||||||
|
info!("poking mi");
|
||||||
|
mi().await?;
|
||||||
|
|
||||||
|
info!("poking bing");
|
||||||
|
bing().await?;
|
||||||
|
|
||||||
|
info!("poking google");
|
||||||
|
google().await?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[instrument(err)]
|
||||||
|
async fn bing() -> Result<()> {
|
||||||
|
let cli = reqwest::Client::new();
|
||||||
|
cli.get("https://www.bing.com/ping")
|
||||||
|
.query(&[("sitemap", "https://christine.website/sitemap.xml")])
|
||||||
|
.header("User-Agent", crate::APPLICATION_NAME)
|
||||||
|
.send()
|
||||||
|
.await?
|
||||||
|
.error_for_status()?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[instrument(err)]
|
||||||
|
async fn google() -> Result<()> {
|
||||||
|
let cli = reqwest::Client::new();
|
||||||
|
cli.get("https://www.google.com/ping")
|
||||||
|
.query(&[("sitemap", "https://christine.website/sitemap.xml")])
|
||||||
|
.header("User-Agent", crate::APPLICATION_NAME)
|
||||||
|
.send()
|
||||||
|
.await?
|
||||||
|
.error_for_status()?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[instrument(err)]
|
||||||
|
async fn cloudflare() -> Result<()> {
|
||||||
|
let cli = cfcache::Client::new(env::var("CF_TOKEN")?, env::var("CF_ZONE_ID")?)?;
|
||||||
|
cli.purge(
|
||||||
|
vec![
|
||||||
|
"https://christine.website/sitemap.xml",
|
||||||
|
"https://christine.website",
|
||||||
|
"https://christine.website/blog",
|
||||||
|
"https://christine.website/blog.atom",
|
||||||
|
"https://christine.website/blog.json",
|
||||||
|
"https://christine.website/blog.rss",
|
||||||
|
"https://christine.website/gallery",
|
||||||
|
"https://christine.website/talks",
|
||||||
|
"https://christine.website/resume",
|
||||||
|
"https://christine.website/signalboost",
|
||||||
|
"https://christine.website/feeds",
|
||||||
|
]
|
||||||
|
.into_iter()
|
||||||
|
.map(|i| i.to_string())
|
||||||
|
.collect(),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[instrument(err)]
|
||||||
|
async fn mi() -> Result<()> {
|
||||||
|
let cli = mi::Client::new(env::var("MI_TOKEN")?, crate::APPLICATION_NAME.to_string())?;
|
||||||
|
cli.refresh().await?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
37
src/main.rs
37
src/main.rs
|
@ -39,21 +39,6 @@ async fn main() -> Result<()> {
|
||||||
.await?,
|
.await?,
|
||||||
);
|
);
|
||||||
|
|
||||||
match sdnotify::SdNotify::from_env() {
|
|
||||||
Ok(ref mut n) => {
|
|
||||||
n.notify_ready().map_err(|why| {
|
|
||||||
error!("can't signal readiness to systemd: {}", why);
|
|
||||||
why
|
|
||||||
})?;
|
|
||||||
n.set_status(format!("hosting {} posts", state.clone().everything.len()))
|
|
||||||
.map_err(|why| {
|
|
||||||
error!("can't signal status to systemd: {}", why);
|
|
||||||
why
|
|
||||||
})?;
|
|
||||||
}
|
|
||||||
Err(why) => error!("not running under systemd with Type=notify: {}", why),
|
|
||||||
}
|
|
||||||
|
|
||||||
let healthcheck = warp::get().and(warp::path(".within").and(warp::path("health")).map(|| "OK"));
|
let healthcheck = warp::get().and(warp::path(".within").and(warp::path("health")).map(|| "OK"));
|
||||||
|
|
||||||
let base = warp::path!("blog" / ..);
|
let base = warp::path!("blog" / ..);
|
||||||
|
@ -222,6 +207,28 @@ async fn main() -> Result<()> {
|
||||||
.with(warp::log(APPLICATION_NAME))
|
.with(warp::log(APPLICATION_NAME))
|
||||||
.recover(handlers::rejection);
|
.recover(handlers::rejection);
|
||||||
|
|
||||||
|
match sdnotify::SdNotify::from_env() {
|
||||||
|
Ok(ref mut n) => {
|
||||||
|
// shitty heuristic for detecting if we're running in prod
|
||||||
|
tokio::spawn(async {
|
||||||
|
if let Err(why) = app::poke::the_cloud().await {
|
||||||
|
error!("Unable to poke the cloud: {}", why);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
n.notify_ready().map_err(|why| {
|
||||||
|
error!("can't signal readiness to systemd: {}", why);
|
||||||
|
why
|
||||||
|
})?;
|
||||||
|
n.set_status(format!("hosting {} posts", state.clone().everything.len()))
|
||||||
|
.map_err(|why| {
|
||||||
|
error!("can't signal status to systemd: {}", why);
|
||||||
|
why
|
||||||
|
})?;
|
||||||
|
}
|
||||||
|
Err(why) => error!("not running under systemd with Type=notify: {}", why),
|
||||||
|
}
|
||||||
|
|
||||||
warp::serve(site)
|
warp::serve(site)
|
||||||
.run((
|
.run((
|
||||||
[0, 0, 0, 0],
|
[0, 0, 0, 0],
|
||||||
|
|
Loading…
Reference in New Issue