English· Español· Deutsch· Nederlands· Français· 日本語· ქართული· 繁體中文· 简体中文· Português· Русский· العربية· हिन्दी· Italiano· 한국어· Polski· Svenska· Türkçe· Українська· Tiếng Việt· Bahasa Indonesia

un

gäst
1 / ?

Form 1: Tillståndsreparation. Form 2: Slösaktig rapport.

Ett mätat hjärta slår på en klocka. Inte på behov. Inte på förändring. På en timer.

Två former, en grundorsak: ett schemalagt jobb som ersätter korrekt design.

Form 1: Tillståndsreparation

En tillståndsövergång misslyckas med att slutföras atomiskt. Istället för att fixa övergången körs ett bakgrundsjobb med fördröjning & avstämmer. Användare ser trasigt tillstånd under avstämningsfönstret.

GitHub-exempel (2026-04-08): En pull request’s upstream-repository blev privat. GitHub försökte göra en tillståndsövergång: stänga PR:en, uppdatera branch-status, rensa merge-status. Övergången slutfördes inte atomiskt. PR-status visade samtidigt ”branch-forced-closed” och ”Merge status cannot be loaded”. En Sidekiq-bakgrundsjobb kördes några minuter senare och slutförde avstämningen. Observatörer såg ett trasigt tillstånd under hela fönstret.

The Metered Heart: Sidekiq-jobbet kördes enligt ett schema. Det kördes inte för att GitHub upptäckte trasigt tillstånd; det kördes för att timern slog. En användare som tittade på PR:en i realtid såg en PR som motsade sig själv tills nästa jobbexekvering.

Form 2: Slösaktig rapport

En rapport eller aggregering beräknas om från början på ett fast intervall. Ingen cache-kontroll. Inget idempotensskydd. Ingen inkrementell uppdatering. Varje körning: en fullständig skanning.

Exempel: ett nattligt cron-jobb som beräknar om varje användares totala köpbelopp genom att skanna alla ordrar från början. Ett dagligt analysjobb som återskapar en dashboard från råa händelseloggar. Ett veckovis sammanfattningsmail som frågar varje rad i aktivitetstabellen.

Varje körning sker oavsett om data har ändrats sedan förra körningen. Varje körning skannar hela historiken även när bara de senaste 24 timmarna innehåller ny data. Varje körning ersätter schemalagd upprepning med inkrementell design.

Den gemensamma roten

Ett Metered Heart kan inte tala sanning om sitt eget tillstånd. Det känner bara klockan. Form 1: tillståndsreparationsjobbet körs vid T+5 minuter oavsett om tillståndet är trasigt vid T+0. Form 2: rapportjobbet körs kl 02:00 oavsett om någon data har ändrats sedan igår.

Klockan bär inte information om vad som behöver göras. En händelse bär den informationen: ”ett tillståndsbyte misslyckades just”, ”nya ordrar anlände just”. Ett Metered Heart kastar bort den informationen och ersätter den med ett schema.

Kapitalförlust

Ett Metered Heart dränerar levande kapital: ingenjörer som är jour för incidenter med trasigt tillstånd. Det urholkar social tillit: användare ser inkonsistent data och rapporterar fel som sedan försvinner av sig själva. Det förstärker andra MOAD:er: ett tillståndsreparationsjobb som skannar alla poster för att hitta trasigt tillstånd innehåller ofta MOAD-0001 (O(N²)-skanning). Ett rapportjobb som beräknar om kalla data kan utlösa MOAD-0005 (cache stampede). MOAD-0009 förvärrar andra defekter.

Den gemensamma roten

Form 1 och Form 2 ser olika ut på ytan: en reparerar tillstånd, en beräknar om data. Rotorsaken förbinder dem.

Form 1 och Form 2 delar en gemensam rotorsak. Beskriv den i en mening. Ge sedan ett exempel på varje form från programvara du har använt.

Fire on Change, Not on Clock

Event-driven design triggar när något ändras. Tillståndsändringen är händelsen. Händelsen är triggaren.

Form 1: den atomära övergången ersätter reparationsjobbet.

Om en tillståndsövergång kan lämna systemet i ett trasigt mellanläge, ligger felet i övergången, inte i avsaknaden av ett reparationsjobb. Fixa övergången så att den slutförs atomiskt (eller transaktionellt). När övergången slutförs atomiskt existerar aldrig trasigt tillstånd. Reparationsjobbet har inget att reparera.

# DEFECT: non-atomic transition leaves broken state
def close_pr_on_repo_private(pr_id):
pr = PR.get(pr_id)
pr.status = 'branch-forced-closed'   # steg 1: partiellt tillstånd
pr.save()                             # synlig för användare NU
# ... andra steg kan misslyckas ...
pr.merge_status = 'not_applicable'
pr.save()                             # steg 2: nu konsekvent
# Sidekiq-job stämmer av om steg 2 misslyckas
# FIX: atomisk övergång; inget mellanliggande tillstånd synligt
def close_pr_on_repo_private(pr_id):
with db.transaction():
pr = PR.get(pr_id)
pr.status = 'branch-forced-closed'
pr.merge_status = 'not_applicable'
pr.save()   # båda fälten sparas atomiskt; aldrig halvt skrivna

Form 2: den inkrementella uppdateringen ersätter den fullständiga omberäkningen.

En rapport som beräknas om från början triggas eftersom gammal data + ny data = nytt resultat. Men det gamla resultatet + delta = samma nya resultat, beräknat inkrementellt. Händelsen: ny data anlände. Triggaren: uppdatera aggregeringen endast för den nya datan.

# FEL: fullständig omberäkning på schema
def nightly_totals_job():
for user in all_users():
total = sum(o.amount for o in user.orders)  # skanna alla tidpunkter
user.total_purchases = total
user.save()

# FIX: händelsedriven inkrementell uppdatering
def on_order_placed(order):
order.user.total_purchases += order.amount   # endast delta
order.user.save()

Den inkrementella uppdateringen triggas när en order anländer, inte klockan 02:00. Den uppdaterar endast den berörda användaren. Den läser endast den nya ordern, inte alla ordrar från all tid. Det nattliga jobbet försvinner.

Varför Form 1 avslöjar en trasig övergång

En Form 1 Metered Heart avslöjar att en tillståndsövergång lämnades ofullständig. Reparationsjobbet finns eftersom en ingenjör upptäckte trasigt tillstånd och lade till en avstämningsmekanism istället för att åtgärda övergången. Reparationsjobbet: en lapp över ett trasigt arkitektoniskt beslut.

MOAD-0009 som förstärkare

MOAD-0009 förstärker andra MOAD:er. Ett tillståndsreparationsjobb som skannar alla poster för att hitta trasigt tillstånd: MOAD-0001 (O(N) eller O(N²)-skanning per körning). Ett rapportjobb som beräknar om allt från grunden: MOAD-0005 (cache stampede när jobbet startar och träffar en varm uppströmskälla). MOAD-0009 skadar inte bara i sig själv; det levererar andra MOAD:er enligt schema.

Diagnostisera & redesigna

Ett team kör ett nattligt cron-jobb klockan 02:00. Jobbet skannar alla ordrar för alla användare och beräknar om varje användares totala köpbelopp från grunden. Jobbet tar 4 timmar. Klockan 06:00 visar instrumentpanelen färska totaler. Mellan 02:00 och 06:00 visar instrumentpanelen gårdagens totaler.

Vilken form av MOAD-0009 är detta? Vilken händelse ska utlösa omberäkning istället? Vilken mellanliggande datastruktur gör uppdateringen inkrementell?