Fix not charging existing relays on reactivation
Docker / build-and-push-image (push) Successful in 50m58s

This commit is contained in:
Jon Staab
2026-06-03 11:29:24 -07:00
parent ffb1491f00
commit a9f66dc3e5
3 changed files with 15 additions and 10 deletions
+6 -4
View File
@@ -89,13 +89,15 @@ impl Billing {
) -> Result<()> {
let mut tenant = tenant.clone();
let activities = query::list_billable_activity(&tenant.pubkey).await?;
let mut activities = query::list_billable_activity(&tenant.pubkey).await?;
// A churned tenant with fresh billable activity is using the service
// again: re-activate billing (and restore their relays) before billing it.
// Reactivation records a billable activity for each restored relay; fold
// those into this pass so their prorated charges land on the same invoice.
if tenant.churned_at.is_some() && !activities.is_empty() {
let relays = query::list_relays_for_tenant(&tenant.pubkey).await?;
command::reactivate_tenant(&tenant.pubkey, &relays).await?;
activities.extend(command::reactivate_tenant(&tenant.pubkey, &relays).await?);
tenant.churned_at = None;
}
@@ -154,12 +156,12 @@ impl Billing {
self.make_prorated_item(tenant, activity, 1, "New relay created")
.await?
}
"activate_relay" => {
"activate_relay" | "unmark_relay_delinquent" => {
self.make_prorated_item(tenant, activity, 1, "Relay reactivated")
.await?
}
"deactivate_relay" => {
self.make_prorated_item(tenant, activity, -1, "Relay deactivated (prorated credit)")
self.make_prorated_item(tenant, activity, -1, "Relay deactivated")
.await?
}
"update_relay" => self.make_plan_change_item(tenant, activity).await?,
+7 -5
View File
@@ -114,8 +114,10 @@ pub async fn churn_tenant(tenant_pubkey: &str, now: i64, relays: &[Relay]) -> Re
}
/// Atomically re-activate a churned tenant: clear the churn marker, restore every
/// delinquent relay to active, and void any still-open invoices.
pub async fn reactivate_tenant(tenant_pubkey: &str, relays: &[Relay]) -> Result<()> {
/// delinquent relay to active, and void any still-open invoices. Returns the
/// `unmark_relay_delinquent` activities recorded for the restored relays, so the
/// caller can fold their prorated charges into the same reconcile pass.
pub async fn reactivate_tenant(tenant_pubkey: &str, relays: &[Relay]) -> Result<Vec<Activity>> {
let activities = with_tx(async |tx| {
set_tenant_churned_at_tx(tx, tenant_pubkey, None).await?;
@@ -135,10 +137,10 @@ pub async fn reactivate_tenant(tenant_pubkey: &str, relays: &[Relay]) -> Result<
})
.await?;
for activity in activities {
publish(activity);
for activity in &activities {
publish(activity.clone());
}
Ok(())
Ok(activities)
}
// --- Relays ---
+2 -1
View File
@@ -233,7 +233,8 @@ pub async fn list_billable_activity(tenant_pubkey: &str) -> Result<Vec<Activity>
"WHERE tenant_pubkey = ?
AND billed_at IS NULL
AND activity_type IN (
'create_relay', 'update_relay', 'activate_relay', 'deactivate_relay'
'create_relay', 'update_relay', 'activate_relay', 'deactivate_relay',
'unmark_relay_delinquent'
)
ORDER BY created_at ASC",
))