mirror of
https://github.com/neondatabase/neon.git
synced 2026-05-19 22:20:37 +00:00
## Problem Part of https://github.com/neondatabase/neon/issues/11813 In PostHog UI, we need to create the properties before using them as a filter. We report all variants automatically when we start the pageserver. In the future, we can report all real tenants instead of fake tenants (we do that now to save money + we don't need real tenants in the UI). ## Summary of changes * Collect `region`, `availability_zone`, `pageserver_id` properties and use them in the feature evaluation. * Report 10 fake tenants on each pageserver startup. --------- Signed-off-by: Alex Chi Z <chi@neon.tech>
88 lines
3.2 KiB
Rust
88 lines
3.2 KiB
Rust
//! A background loop that fetches feature flags from PostHog and updates the feature store.
|
|
|
|
use std::{sync::Arc, time::Duration};
|
|
|
|
use arc_swap::ArcSwap;
|
|
use tokio_util::sync::CancellationToken;
|
|
use tracing::{Instrument, info_span};
|
|
|
|
use crate::{CaptureEvent, FeatureStore, PostHogClient, PostHogClientConfig};
|
|
|
|
/// A background loop that fetches feature flags from PostHog and updates the feature store.
|
|
pub struct FeatureResolverBackgroundLoop {
|
|
posthog_client: PostHogClient,
|
|
feature_store: ArcSwap<FeatureStore>,
|
|
cancel: CancellationToken,
|
|
}
|
|
|
|
impl FeatureResolverBackgroundLoop {
|
|
pub fn new(config: PostHogClientConfig, shutdown_pageserver: CancellationToken) -> Self {
|
|
Self {
|
|
posthog_client: PostHogClient::new(config),
|
|
feature_store: ArcSwap::new(Arc::new(FeatureStore::new())),
|
|
cancel: shutdown_pageserver,
|
|
}
|
|
}
|
|
|
|
pub fn spawn(
|
|
self: Arc<Self>,
|
|
handle: &tokio::runtime::Handle,
|
|
refresh_period: Duration,
|
|
fake_tenants: Vec<CaptureEvent>,
|
|
) {
|
|
let this = self.clone();
|
|
let cancel = self.cancel.clone();
|
|
|
|
// Main loop of updating the feature flags.
|
|
handle.spawn(
|
|
async move {
|
|
tracing::info!("Starting PostHog feature resolver");
|
|
let mut ticker = tokio::time::interval(refresh_period);
|
|
ticker.set_missed_tick_behavior(tokio::time::MissedTickBehavior::Skip);
|
|
loop {
|
|
tokio::select! {
|
|
_ = ticker.tick() => {}
|
|
_ = cancel.cancelled() => break
|
|
}
|
|
let resp = match this
|
|
.posthog_client
|
|
.get_feature_flags_local_evaluation()
|
|
.await
|
|
{
|
|
Ok(resp) => resp,
|
|
Err(e) => {
|
|
tracing::warn!("Cannot get feature flags: {}", e);
|
|
continue;
|
|
}
|
|
};
|
|
let feature_store = FeatureStore::new_with_flags(resp.flags);
|
|
this.feature_store.store(Arc::new(feature_store));
|
|
tracing::info!("Feature flag updated");
|
|
}
|
|
tracing::info!("PostHog feature resolver stopped");
|
|
}
|
|
.instrument(info_span!("posthog_feature_resolver")),
|
|
);
|
|
|
|
// Report fake tenants to PostHog so that we have the combination of all the properties in the UI.
|
|
// Do one report per pageserver restart.
|
|
let this = self.clone();
|
|
handle.spawn(
|
|
async move {
|
|
tracing::info!("Starting PostHog feature reporter");
|
|
for tenant in &fake_tenants {
|
|
tracing::info!("Reporting fake tenant: {:?}", tenant);
|
|
}
|
|
if let Err(e) = this.posthog_client.capture_event_batch(&fake_tenants).await {
|
|
tracing::warn!("Cannot report fake tenants: {}", e);
|
|
}
|
|
}
|
|
.instrument(info_span!("posthog_feature_reporter")),
|
|
);
|
|
}
|
|
|
|
pub fn feature_store(&self) -> Arc<FeatureStore> {
|
|
self.feature_store.load_full()
|
|
}
|
|
}
|