Εγγυήσεις και όρια
Είναι εύκολο να δείξει κανείς υπερβολική εμπιστοσύνη σε έναν scheduler. Αυτή η σελίδα δηλώνει με ακρίβεια τι εγγυάται το anarchon και πού σταματά η εγγύηση.
Τι εγγυάται
Ενότητα με τίτλο «Τι εγγυάται»Ένας νικητής ανά προσπάθεια
Ενότητα με τίτλο «Ένας νικητής ανά προσπάθεια»Για μία εργασία και μία χρονική θυρίδα, μόνο ένα instance κερδίζει κάθε προσπάθεια. Αυτό ισχύει σε κάθε backend, επειδή η διεκδίκηση είναι ένα ενιαίο ατομικό βήμα στο store.
Δεύτερη προσπάθεια μόνο αφού η πρώτη σταματήσει να ανανεώνει
Ενότητα με τίτλο «Δεύτερη προσπάθεια μόνο αφού η πρώτη σταματήσει να ανανεώνει»Backends μίσθωσης. Μια εκτέλεση λαμβάνει άλλη προσπάθεια μόνο όταν ο runner της σταματήσει να ανανεώνει τη μίσθωση, ή την αποδεσμεύσει κατά το stop(). Ένας υγιής runner δεν αντικαθίσταται ποτέ.
Όχι δύο ζωντανές εκτελέσεις της ίδιας εργασίας
Ενότητα με τίτλο «Όχι δύο ζωντανές εκτελέσεις της ίδιας εργασίας»Backends μίσθωσης, overlap: 'skip'. Μια νέα εκτέλεση μιας εργασίας δεν ξεκινά όσο μια προηγούμενη εκτέλεση της ίδιας εργασίας διατηρεί ενεργή μίσθωση.
Μια εκτέλεση που κατέρρευσε ξεκινά ξανά
Ενότητα με τίτλο «Μια εκτέλεση που κατέρρευσε ξεκινά ξανά»Backends μίσθωσης. Εάν ο runner καταρρεύσει, ένα εφεδρικό instance ξεκινά την εκτέλεση ξανά, έως και maxAttempts φορές, εκτός εάν ξεκινήσει πρώτα μια νεότερη εκτέλεση της εργασίας.
Οι παρωχημένες εκτελέσεις δεν ξεκινούν
Ενότητα με τίτλο «Οι παρωχημένες εκτελέσεις δεν ξεκινούν»Μια εκτέλεση δεν ξεκινά περισσότερο από maxLateMs μετά την ώρα της. Σε backends μίσθωσης αυτό ελέγχεται επίσης στο ρολόι του store, επομένως μια καθυστερημένη ή σε ουρά διεκδίκηση δεν μπορεί να ξεκινήσει καμία.
Ένας παλιός runner δεν μπορεί να αλλάξει μια εκτέλεση
Ενότητα με τίτλο «Ένας παλιός runner δεν μπορεί να αλλάξει μια εκτέλεση»Backends μίσθωσης. Μετά από μια ανάληψη, τα heartbeats και το “finished” του προηγούμενου runner απορρίπτονται.
Τι δεν εγγυάται
Ενότητα με τίτλο «Τι δεν εγγυάται»Εκτέλεση ακριβώς μία φορά
Ενότητα με τίτλο «Εκτέλεση ακριβώς μία φορά»Το anarchon παρέχει εκτέλεση τουλάχιστον μία φορά για εκτελέσεις των οποίων ο runner καταρρέει. Ένας handler μπορεί να εκτελεστεί περισσότερες από μία φορές για την ίδια θυρίδα:
- Ένας runner καταρρέει αφού ολοκληρώσει τη μισή δουλειά. Η Προσπάθεια 2 ξεκινά από την αρχή.
- Ένας runner παγώνει, ένα εφεδρικό instance αναλαμβάνει, και ο παγωμένος runner ξυπνά και εκτελείται λίγο ακόμα πριν μάθει ότι έχασε την εκτέλεση.
Κανένας scheduler δεν μπορεί να παρέχει εκτέλεση ακριβώς μία φορά για αυθαίρετο κώδικα: το σύστημα δεν μπορεί να διακρίνει το «η δουλειά έγινε και η επιβεβαίωση χάθηκε» από το «η δουλειά δεν έγινε». Αυτό που μπορεί να κάνει είναι να σας δώσει ένα σταθερό κλειδί, το ctx.slot, ώστε να μπορείτε να κάνετε την εργασία idempotent.
Τι να κάνετε: κάντε τις εργασίες ασφαλείς για διπλή εκτέλεση.
Ότι κάθε θυρίδα θα εκτελεστεί
Ενότητα με τίτλο «Ότι κάθε θυρίδα θα εκτελεστεί»Μια εκτέλεση μπορεί να παραλειφθεί, βάσει σχεδιασμού:
| Πότε | Γιατί |
|---|---|
| Η προηγούμενη εκτέλεση βρίσκεται ακόμη σε εξέλιξη | overlap: 'skip' |
Κάθε instance ήταν εκτός λειτουργίας για περισσότερο από catchUpMs |
Η ανάκτηση καλύπτει μόνο την πιο πρόσφατη εκτέλεση, και μόνο εάν είναι πρόσφατη |
| Το instance καθυστέρησε υπερβολικά | maxLateMs |
| Ένας runner κατέρρευσε και μια νεότερη εκτέλεση της εργασίας ξεκίνησε πρώτη | Η νεότερη εκτέλεση την αντικαθιστά |
| Το store δεν ήταν προσβάσιμο όταν έπρεπε να τρέξει η εκτέλεση | Κανείς δεν μπόρεσε να τη διεκδικήσει. Τα instances που τρέχουν περιμένουν την επόμενη θυρίδα· σε backend μίσθωσης ανακτάται μόνο εάν ένα instance ξεκινήσει εντός catchUpMs αφού επανέλθει το store |
Το anarchon δεν είναι ουρά εργασιών προς εκτέλεση. Εάν κάθε θυρίδα πρέπει να παραγάγει αποτέλεσμα, ρυθμίστε κάθε εκτέλεση να δουλεύει σε ό,τι εκκρεμεί αντί μόνο στη «δική της» θυρίδα:
scheduler.every('send-pending-emails', '1m', async (ctx) => { for (const email of await pendingEmails()) { // ό,τι εκκρεμεί ctx.signal.throwIfAborted(); await send(email); }});Μια εκτέλεση που παραλείπεται κοστίζει τότε μόνο μια καθυστέρηση, όχι χαμένη δουλειά.
Ακριβείς χρόνοι έναρξης
Ενότητα με τίτλο «Ακριβείς χρόνοι έναρξης»Μια εκτέλεση ξεκινά μεταξύ της θυρίδας της και του slot + jitterMs, σε κάποιο instance. Μην βασίζεστε στο ότι η εκκίνηση θα είναι ακριβής· χρησιμοποιήστε το ctx.scheduledAt για την ονομαστική ώρα.
Σειρά μεταξύ διαφορετικών εργασιών
Ενότητα με τίτλο «Σειρά μεταξύ διαφορετικών εργασιών»Διαφορετικές εργασίες είναι ανεξάρτητες. Δύο εργασίες που πρέπει να τρέξουν την ίδια στιγμή μπορεί να εκτελεστούν σε διαφορετικά instances, με οποιαδήποτε σειρά.
Οτιδήποτε σε backends μόνο-διεκδίκησης πέρα από τη διεκδίκηση
Ενότητα με τίτλο «Οτιδήποτε σε backends μόνο-διεκδίκησης πέρα από τη διεκδίκηση»Με το RabbitMQ, το NATS και τις στρατηγικές Redis stream-id, idmp και script, μια εκτέλεση της οποίας ο runner καταρρέει είναι χαμένη. Δεν υπάρχουν εφεδρικά instances, καμία προστασία αλληλεπικάλυψης και καμία ανάκτηση.
Τι πρέπει να παρέχει το store
Ενότητα με τίτλο «Τι πρέπει να παρέχει το store»Το anarchon είναι τόσο αξιόπιστο όσο το store του.
| Εάν το store | Τότε |
|---|---|
| Δεν είναι προσβάσιμο | Καμία εκτέλεση δεν μπορεί να διεκδικηθεί. Οι εκτελούμενες εργασίες συνεχίζονται, αλλά δεν μπορούν να ανανεώσουν: μετά από leaseMs θεωρούνται νεκρές |
| Χάνει επιβεβαιωμένες εγγραφές (ασύγχρονος συγχρονισμός με failover) | Μια διεκδικημένη εκτέλεση μπορεί να φαίνεται αδέσμευτη, και να εκτελεστεί ξανά |
| Έχει πολλαπλά primaries που δέχονται τις ίδιες εγγραφές | Η ατομική διεκδίκηση παύει να ισχύει |
Χρησιμοποιήστε ένα store ρυθμισμένο για ανθεκτικότητα κατάλληλη για τις εργασίες σας. Για εργασίες όπου ένα σπάνιο διπλότυπο είναι απαράδεκτο, η πραγματική προστασία είναι το idempotency στον handler, όχι το store.
Ρολόγια
Ενότητα με τίτλο «Ρολόγια»| Υπόθεση | Εάν δεν ισχύει |
|---|---|
| Τα ρολόγια των instances συμφωνούν εντός περίπου ενός δευτερολέπτου | Το πιο γρήγορο instance κερδίζει συχνότερα. Τίποτα δεν χαλάει |
Τα ρολόγια συμφωνούν εντός maxLateMs |
Ένα instance πολύ πίσω βλέπει τις εκτελέσεις του να απορρίπτονται ως καθυστερημένες· ένα πολύ μπροστά διεκδικεί νωρίς |
| Το ρολόι του store κινείται σταθερά προς τα εμπρός | Οι μισθώσεις υπολογίζονται πάνω σε αυτό. Ένα άλμα προς τα εμπρός μπορεί να λήξει τις μισθώσεις πρόωρα |
Εκτελέστε NTP ή το συγχρονισμό ώρας της πλατφόρμας σας.
| Όριο | Τιμή |
|---|---|
| Μικρότερο μεσοδιάστημα | 1 δευτερόλεπτο |
Όριο history() |
1 έως 10000 |
maxAttempts |
1 έως 100 |
| Αποθηκευμένο μήνυμα σφάλματος | 2000 χαρακτήρες |
| Μεγαλύτερο εσωτερικό χρονόμετρο | 1 λεπτό, μετά το ρολόι διαβάζεται ξανά |
| Node.js | 20 ή νεότερο |
Ένας handler γραμμένος για αυτές τις εγγυήσεις
Ενότητα με τίτλο «Ένας handler γραμμένος για αυτές τις εγγυήσεις»scheduler.every( 'settle-payments', '5m', async (ctx) => { // Το ίδιο παράθυρο σε κάθε προσπάθεια const to = ctx.slot; const from = to - 5 * 60_000;
for (const payment of await unsettledBetween(from, to)) { ctx.signal.throwIfAborted(); // διακοπή όταν ζητηθεί await settle(payment, { idempotencyKey: payment.id }); // ασφαλές να επαναληφθεί } }, { timeoutMs: 4 * 60_000, // δεν μπορεί να κολλήσει για πάντα maxAttempts: 3, // επαναλαμβάνεται εάν ο runner καταρρεύσει },);Αναβαθμίσεις
Ενότητα με τίτλο «Αναβαθμίσεις»- Τα rolling deploys μέσα σε μία major έκδοση υποστηρίζονται. Instances σε δύο εκδόσεις της ίδιας major έκδοσης μπορούν να μοιράζονται ένα store όσο απλώνεται η νέα: τα δεδομένα μόνο επεκτείνονται, και κάθε έκδοση κρατά τα πεδία που δεν γνωρίζει.
- Το store καταγράφει τη μορφή του. Αν μια έκδοση χρειαστεί ποτέ να αλλάξει τη διάταξη με τρόπο που οι παλαιότερες εκδόσεις δεν μπορούν να διαβάσουν, το changelog της το αναφέρει, όλα τα instances πρέπει να σταματήσουν πριν από την αναβάθμιση, και ένα παλαιότερο instance που συναντά τα νέα δεδομένα αρνείται να ξεκινήσει (
ANARCHON_STORE_FORMAT) αντί να τα διαβάσει λάθος. - Τρέξτε μία έκδοση σε όλα τα instances μιας υπηρεσίας όταν ολοκληρωθεί το deploy. Οι χρόνοι εκτέλεσης προκύπτουν από τη βιβλιοθήκη cron από την οποία εξαρτάται το anarchon, και τα instances πρέπει να υπολογίζουν τους ίδιους.