Fault tolerance, skip- og retry-politikker
Konfigurér skip-, retry- og restart-semantik for at gøre jobs robuste over for midlertidige datafejl.
Fault tolerance, skip- og retry-politikker er en gratis Komplet guide til Spring Boot 4-lektion på CoddyKit. Dette er lektion 3 af 4. Du kan læse alle 3 lektioner i dette læringsspor gratis i deres fulde længde — derefter låser CoddyKit PRO alle lektioner op samt praktiske øvelser med en indbygget kodeeditor og en AI-underviser døgnet rundt. Den er en del af læringsforløbet i Komplet guide til Spring Boot 4, og dine fremskridt synkroniseres på tværs af nettet og CoddyKit-appen. Komplet guide til Spring Boot 4-kurset indeholder 4 lektioner i alt.
Hvorfor fejltolerance er vigtig
Batchjob behandler enorme datamængder, og data fra den virkelige verden er ofte uensartede. En enkelt fejlformateret række, en kortvarig deadlock i databasen eller et ustabilt kald til et nedstrømssystem kan få et job til at mislykkes, selv efter at det har behandlet millioner af poster.
Spring Batch giver et chunk-orienteret trin fejltolerance, så det kan håndtere disse problemer uden at afbryde hele kørslen. De tre centrale værktøjer er:
- Spring over — kassér poster, der forårsager uoprettelige fejl (f.eks. ugyldige data), og fortsæt.
- Prøv igen — gentag en handling, der mislykkede på grund af en midlertidig fejl (f.eks. en timeout ved låsning).
- Genstart — genoptag en mislykket jobinstans fra det sted, hvor den stoppede, i stedet for at begynde forfra.
Brugt sammen forvandler de et skrøbeligt job til et robust job.
Aktivering af fejltolerance på et trin
Fejltolerance er et aktivt valg. Når du opbygger et chunk-trin, skal du kalde .faultTolerant() på trinbyggeren for at skifte til den fejltolerante variant. Først derefter kan du erklære regler for at springe over og prøve igen.
Uden .faultTolerant() tilbagefører enhver undtagelse fra en læser, processor eller skriver chunken og får straks trinnet til at mislykkes.
@Bean
public Step importStep(JobRepository jobRepository,
PlatformTransactionManager txManager,
ItemReader<Customer> reader,
ItemProcessor<Customer, Customer> processor,
ItemWriter<Customer> writer) {
return new StepBuilder("importStep", jobRepository)
.<Customer, Customer>chunk(100, txManager)
.reader(reader)
.processor(processor)
.writer(writer)
.faultTolerant() // unlocks skip & retry configuration
.build();
}Konfiguration af regler for at springe over
Med spring over kan trinnet kassere et enkelt element, som aldrig kan lykkes — typisk på grund af en fejl ved fortolkning eller validering — og fortsætte med det næste.
Du angiver, hvilke undtagelser der kan springes over, samt en samlet grænse:
.skip(Exception.class)— markér en undtagelsestype som mulig at springe over..noSkip(Exception.class)— udeluk udtrykkeligt en undertype fra at kunne springes over..skipLimit(n)— det samlede antal tilladte spring over, før trinnet mislykkes.
Når det samlede antal overskrider skipLimit, afbrydes trinnet. Det forhindrer, at et job i stilhed sluger tusindvis af ugyldige poster.
return new StepBuilder("importStep", jobRepository)
.<Customer, Customer>chunk(100, txManager)
.reader(reader)
.processor(processor)
.writer(writer)
.faultTolerant()
.skip(FlatFileParseException.class) // bad CSV line
.skip(ValidationException.class) // failed bean validation
.noSkip(FileNotFoundException.class) // never skip this
.skipLimit(50) // fail after 50 skips
.build();Sådan påvirker spring over chunks
Hvordan spring over fungerer, afhænger af, hvor undtagelsen opstår:
- Spring over i læseren: Det ugyldige element kasseres, og læsningen fortsætter — billigt og uden tilbageførsel.
- Spring over i processoren: Chunkens transaktion tilbageføres, hvorefter Spring Batch behandler chunken igen element for element og kun springer det problematiske element over.
- Spring over i skriveren: Samme gennemgang og nye forsøg — chunken tilbageføres, og elementerne skrives igen ét ad gangen, så det ene ugyldige element kan isoleres og springes over.
Fordi spring over i processor eller skriver udløser tilbageførsel og gentagelse af enkeltelementer, er de langt dyrere end spring over i læseren. Placér så vidt muligt valideringen i læseren eller processoren, så fejl opdages tidligt.
En brugerdefineret SkipPolicy
Den deklarative .skip()/.skipLimit()-API dækker de fleste tilfælde, men du kan implementere SkipPolicy til helt tilpasset logik — f.eks. tillade flere spring over for én undtagelsestype end for en anden eller undersøge undtagelsens meddelelse.
Metoden shouldSkip modtager den udløste Throwable og det aktuelle antal spring over. Returnér true for at springe over, eller kast SkipLimitExceededException for at få trinnet til at mislykkes.
public class CustomSkipPolicy implements SkipPolicy {
@Override
public boolean shouldSkip(Throwable t, long skipCount)
throws SkipLimitExceededException {
if (t instanceof FileNotFoundException) {
return false; // fatal: never skip
}
if (t instanceof ValidationException && skipCount < 100) {
return true; // tolerate up to 100 bad records
}
if (t instanceof FlatFileParseException && skipCount < 20) {
return true;
}
return false;
}
}Hvornår skal du prøve igen eller springe over?
Valget mellem at springe over og prøve igen afhænger af fejlens karakter:
- Prøv igen ved en midlertidig fejl, der måske lykkes ved et nyt forsøg: deadlock-offer, timeout ved låsning, konflikt ved optimistisk låsning eller et kortvarigt netværksudfald.
- Spring over ved en deterministisk fejl, der altid vil mislykkes: fejlformaterede inddata, en mislykket forretningsvalidering eller en begrænsning, som selve dataene overtræder.
Hvis du prøver igen ved en deterministisk fejl, spilder du blot forsøg, før det mislykkes. Hvis du springer over ved en midlertidig fejl, kasserer du data, der ellers ville være lykkedes. Klassificér dine undtagelser korrekt — det er lektionens vigtigste designbeslutning.
Konfiguration af regler for nye forsøg
Retry forsøger den fejlslagne handling igen op til et konfigureret antal gange, før den giver op. På et fejltolerant trin angiver du:
.retry(Exception.class)— undtagelsestyper, der kan udløse nye forsøg..noRetry(Exception.class)— udeluk en undertype..retryLimit(n)— maksimalt antal forsøg pr. element (inklusive det første forsøg).
Når et element fejler med en undtagelse, der kan udløse nye forsøg, rulles chunk-transaktionen tilbage, og elementet behandles igen op til retryLimit gange. Hvis det stadig fejler, sendes undtagelsen videre — og på det tidspunkt kan den springes over, hvis den også er angivet som mulig at springe over.
return new StepBuilder("importStep", jobRepository)
.<Customer, Customer>chunk(100, txManager)
.reader(reader)
.processor(processor)
.writer(writer)
.faultTolerant()
.retry(DeadlockLoserDataAccessException.class)
.retry(OptimisticLockingFailureException.class)
.retryLimit(3) // up to 3 attempts per item
.skip(ValidationException.class)
.skipLimit(50)
.build();Ventetid mellem nye forsøg
Hvis du gentagne gange forsøger at tilgå en ressource med høj belastning uden ventetid, gør det ofte konkurrencen om ressourcen værre. En backoff-politik indsætter en forsinkelse mellem forsøgene. ExponentialBackOffPolicy øger ventetiden multiplikativt, så belastningen spredes ud.
Du tilknytter en brugerdefineret RetryPolicy eller BackOffPolicy via .retryPolicy(...) eller ved at konfigurere en RetryTemplate. Herunder starter ventetiden ved 200 ms og fordobles ved hvert forsøg, op til 5 sekunder.
@Bean
public RetryTemplate retryTemplate() {
ExponentialBackOffPolicy backOff = new ExponentialBackOffPolicy();
backOff.setInitialInterval(200); // 200 ms
backOff.setMultiplier(2.0); // 200, 400, 800, ...
backOff.setMaxInterval(5000); // cap at 5 s
SimpleRetryPolicy retryPolicy = new SimpleRetryPolicy(3,
Map.of(DeadlockLoserDataAccessException.class, true));
RetryTemplate template = new RetryTemplate();
template.setBackOffPolicy(backOff);
template.setRetryPolicy(retryPolicy);
return template;
}Lyttere: Overvågning af over-springninger og nye forsøg
Det er farligt at springe poster over uden at registrere det — du har brug for et revisionsspor. Tilbagekald fra SkipListener udføres for hvert element, der springes over, så du kan logge det, skrive det til en tabel for fejlslagne poster eller sende en alarm.
onSkipInRead— en læsefejl blev sprunget over.onSkipInProcess— giver dig elementet og undtagelsen.onSkipInWrite— elementet, der ikke kunne skrives.
Registrer den med .listener(skipListener) i trinbyggeren. Der findes også en RetryListener til overvågning af nye forsøg.
public class LoggingSkipListener implements SkipListener<Customer, Customer> {
private static final Logger log =
LoggerFactory.getLogger(LoggingSkipListener.class);
@Override
public void onSkipInRead(Throwable t) {
log.warn("Skipped unreadable record: {}", t.getMessage());
}
@Override
public void onSkipInProcess(Customer item, Throwable t) {
log.warn("Skipped {} in process: {}", item.getId(), t.getMessage());
}
@Override
public void onSkipInWrite(Customer item, Throwable t) {
log.warn("Skipped {} in write: {}", item.getId(), t.getMessage());
}
}Mulighed for genstart og joblageret
Over-springning og nye forsøg håndterer fejl inden for en kørsel; genstart håndterer en kørsel, der mislykkedes fuldstændigt. Spring Batch gemmer hvert trins ExecutionContext samt antallet af læste og skrevne elementer i jobrepositoryet, så en genstart af den samme JobInstance fortsætter fra den senest bekræftede chunk i stedet for at behandle alt igen.
Vigtige regler:
- En
JobInstanceidentificeres af dens identificerende jobparametre. Genbrug dem for at genstarte, og ændr dem for at starte en ny instans. - Kun jobs i en tilstand, der ikke er
COMPLETED(f.eks.FAILEDellerSTOPPED), kan genstartes. - Markér et trin med
.allowStartIfComplete(true)for at tvinge allerede fuldførte trin til at køre igen ved en genstart. - Begræns antallet af nye forsøg med
.startLimit(n), så et fejlbehæftet trin ikke genstartes for evigt.
Samling af det hele
Et robust trin, der er klar til produktion, kombinerer alle tre hensyn: Forsøg igen ved midlertidige fejl med backoff, spring deterministisk ugyldige data over inden for en fastsat grænse, registrer hver over-springning, og stol på joblageret ved genstarter.
Bemærk lagdelingen: Et element, der fejler, forsøges først igen. Hvis det stadig fejler, og undtagelsen kan springes over, springes elementet over (og lytteren registrerer det). Undtagelser kan både udløse nye forsøg og kunne springes over — først bruges alle nye forsøg, derefter anvendes over-springning.
return new StepBuilder("resilientImport", jobRepository)
.<Customer, Customer>chunk(100, txManager)
.reader(reader)
.processor(processor)
.writer(writer)
.faultTolerant()
// transient -> retry with backoff
.retry(DeadlockLoserDataAccessException.class)
.retryLimit(3)
// deterministic bad data -> skip
.skip(FlatFileParseException.class)
.skip(ValidationException.class)
.skipLimit(100)
// audit + restart safety
.listener(new LoggingSkipListener())
.startLimit(3)
.build();Hurtigt tjek
Test din forståelse af betydningen af at springe over kontra at forsøge igen.
Opsummering
Du har gjort et Spring Batch-trin robust over for midlertidige og deterministiske fejl:
- Aktivér tolerance med
.faultTolerant(), før du angiver regler for over-springning eller nye forsøg. - Spring deterministisk ugyldige data over med
.skip()+.skipLimit(). Over-springning i processor eller writer koster en rollback og gentagen behandling af ét element, så valider tidligt. - Forsøg igen ved midlertidige fejl med
.retry()+.retryLimit(), og tilføj en eksponentiel backoff for at mindske konkurrencen om ressourcer. - Klassificér omhyggeligt: Forsøg igen ved midlertidige fejl (deadlock, lock-timeout), og spring deterministiske fejl over (parsing eller validering). Når en undtagelse er begge dele, udføres nye forsøg først, derefter over-springning.
- Registrér hver over-springning med en
SkipListener, så intet forsvinder ubemærket. - Genstart fejlslagne instanser fra den senest bekræftede chunk via joblageret. Styr genkørsler med
allowStartIfCompleteogstartLimit.
Lær Java med en AI-underviser — gratis
Skriv og kør rigtig kode i din browser, få øjeblikkelig hjælp fra en AI-underviser døgnet rundt, og fortsæt, hvor du slap, på web eller i appen.
- Kurser
- 21
- Lektioner
- 84
Ofte stillede spørgsmål
Er lektionen “Fault tolerance, skip- og retry-politikker” gratis?
Ja — alle 3 lektioner i læringssporet Komplet guide til Spring Boot 4, inklusive “Fault tolerance, skip- og retry-politikker”, kan læses gratis i deres fulde længde her på webstedet. Derefter låser CoddyKit PRO alle lektioner op samt interaktive øvelser med en indbygget kodeeditor og en AI-underviser døgnet rundt. Komplet guide til Spring Boot 4-kurset indeholder 4 lektioner i alt.
Hvad lærer jeg i “Fault tolerance, skip- og retry-politikker”?
Konfigurér skip-, retry- og restart-semantik for at gøre jobs robuste over for midlertidige datafejl. Du øver dig i Komplet guide til Spring Boot 4 med praktisk kode, som du kører direkte i browseren, og en AI-vejleder døgnet rundt besvarer dine spørgsmål, mens du arbejder dig gennem lektionen.
Skal jeg have erfaring for at begynde på Komplet guide til Spring Boot 4?
Der kræves ingen tidligere erfaring. Komplet guide til Spring Boot 4 på CoddyKit er tilrettelagt for både begyndere og øvede, så du kan starte her eller fra begyndelsen og lære i dit eget tempo. Dette er lektion 3 af 4.
Hvor lang tid tager lektionen “Fault tolerance, skip- og retry-politikker”?
De fleste CoddyKit-lektioner tager cirka 5–10 minutter. Hver lektion er kort og interaktiv, så du gør løbende fremskridt og kan fortsætte, hvor du slap – på både web og app.
Kan jeg skrive og køre kode i denne Komplet guide til Spring Boot 4-lektion?
Ja. Alle Komplet guide til Spring Boot 4-lektioner har en indbygget kodeeditor, så du kan skrive og køre rigtig kode direkte i din browser og få øjeblikkelig feedback fra AI – uden lokal opsætning.
Alle lektioner i dette kursus
- Jobs, steps og JobRepository-modellen
- Chunk-orienterede reader-processor-writer-flows
- Fault tolerance, skip- og retry-politikker
- Partitionering og parallel step-eksekvering