Redis και Valkey
Το Redis είναι το προεπιλεγμένο backend. Το RedisBackend λειτουργεί με Redis 5 ή νεότερο, και το ValkeyBackend με Valkey.
import { RedisBackend, Scheduler, ValkeyBackend } from 'anarchon';
new Scheduler({ backend: new RedisBackend({ redis: 'redis://localhost:6379' }) });new Scheduler({ backend: new RedisBackend({ redis: 'redis://cache.internal:6379' }) });new Scheduler({ backend: new ValkeyBackend({ valkey: { host: 'localhost', port: 6390 } }) });Το ValkeyBackend είναι ένα RedisBackend που δέχεται μόνο τις στρατηγικές που υποστηρίζει το Valkey, οπότε το strategy: 'idmp' είναι σφάλμα τύπου αντί για σφάλμα από το start(). Η επιλογή σύνδεσής του είναι valkey αντί για redis, και δεν έχει ρυθμίσεις idmp. Όλα τα υπόλοιπα αυτής της σελίδας ισχύουν και για τα δύο.
Σύνδεση
Ενότητα με τίτλο «Σύνδεση»Η παράμετρος redis δέχεται ένα URL, ένα αντικείμενο επιλογών (options object) ή έναν client.
new Scheduler({ backend: new RedisBackend({ redis: process.env.REDIS_URL }) }); // rediss:// για TLS· χρήστης, κωδικός και βάση δεδομένων μπαίνουν στο URLnew Scheduler({ backend: new RedisBackend({ redis: { host: 'cache', port: 6379, password: process.env.REDIS_PASSWORD, db: 1 } }) });Όταν περνάτε ένα URL ή επιλογές, το anarchon ανοίγει τη σύνδεση με το redis (node-redis) και την κλείνει κατά την κλήση του stop().
Ο δικός σας client
Ενότητα με τίτλο «Ο δικός σας client»import { Redis } from 'ioredis';
const redis = new Redis(process.env.REDIS_URL);const scheduler = new Scheduler({ backend: new RedisBackend({ redis }) }); // το stop() τον αφήνει ανοιχτόΑναγνωρίζονται οι εξής clients: ioredis, iovalkey, node-redis (redis) και Valkey GLIDE. Οποιοσδήποτε άλλος λειτουργεί εφόσον διαθέτει μέθοδο send(command, args) που επιστρέφει την απόκριση.
Επιλογές
Ενότητα με τίτλο «Επιλογές»Επιλογές του new RedisBackend(). Το new ValkeyBackend() δέχεται τις ίδιες, με valkey στη θέση του redis και χωρίς τη στρατηγική 'idmp':
| Επιλογή | Προεπιλογή | Σημασία |
|---|---|---|
redis |
localhost:6379 |
Σύνδεση ή client |
strategy |
'lease' |
Πώς επιλέγεται ένας νικητής: ένα όνομα, ή { name, ...ρυθμίσεις } (παρακάτω) |
prefix |
'cron:' |
Πρόθεμα κάθε κλειδιού |
Οι ρυθμίσεις μιας στρατηγικής μπαίνουν μέσα της, ώστε μια επιλογή που δεν χρησιμοποιεί η στρατηγική να μην μπορεί να οριστεί κατά λάθος: το { name: 'lease', windowMs: 1 } είναι σφάλμα τύπου, και σφάλμα όταν δημιουργείται το backend.
import { RedisBackend, Scheduler } from 'anarchon';
const backend = new RedisBackend({ redis: process.env.REDIS_URL, strategy: { name: 'script', windowMs: 10 * 60_000 }, prefix: 'billing:cron:',});new Scheduler({ backend });Μόνο το lease δίνει στον scheduler μισθώσεις. Με τις άλλες στρατηγικές, οι επιλογές μίσθωσης (overlap, maxAttempts και catchUpMs στις εργασίες, leaseMs και heartbeatMs στον scheduler) δεν προσφέρονται από τους τύπους και απορρίπτονται αν οριστούν: δείτε Brokers και μισθώσεις.
Στρατηγικές
Ενότητα με τίτλο «Στρατηγικές»Μια στρατηγική είναι η εντολή που επιτρέπει σε ακριβώς ένα instance να κερδίσει. Το Redis εκτελεί εντολές και Lua scripts μία-μία τη φορά, επομένως οποιαδήποτε μεμονωμένη εντολή ή script που ελέγχει ταυτόχρονα αν «είναι δεσμευμένη αυτή η εκτέλεση;» και τη δεσμεύει, είναι ατομική.
| Στρατηγική | Μισθώσεις (Leases) | Λειτουργεί σε | Απομνημονεύει μια εκτέλεση για |
|---|---|---|---|
lease (προεπιλογή) |
ναι | Redis 5+, Valkey | όσο διάστημα θα μπορούσε να τη ζητήσει ένα καθυστερημένο claim |
stream-id |
όχι | Redis 5+, Valkey | για πάντα |
idmp |
όχι | Redis 8.6+ μόνο | strategy.durationSec (5 λεπτά) |
script |
όχι | Redis 5+, Valkey | strategy.windowMs (5 λεπτά) |
Χρησιμοποιήστε τη στρατηγική lease εκτός αν έχετε λόγο να μην το κάνετε. Είναι η μόνη στρατηγική με backups, προστασία επικάλυψης, επαναπροσπάθειες και ανάκτηση (catch-up). Οι άλλες αποφασίζουν μόνο ποιος εκτελεί κάθε φορά· διατηρούνται για ελάχιστες ρυθμίσεις και για σύγκριση.
Ένα Lua script διαβάζει την κατάσταση της εκτέλεσης και αποφασίζει:
flowchart TD
claim["claim(job, slot, token)"] --> has{"κατάσταση για αυτή την εκτέλεση;"}
has -- "καμία" --> overlap{"παλαιότερη εκτέλεση της εργασίας<br/>με ενεργή μίσθωση;"}
overlap -- "ναι" --> ovl["απάντηση: overlap"]
overlap -- "όχι" --> won1["αποθήκευση attempt 1, token, λήξη μίσθωσης<br/>απάντηση: won"]
has -- "finished" --> done["απάντηση: done"]
has -- "running" --> alive{"λήξη μίσθωσης στο μέλλον;"}
alive -- "ναι" --> running["απάντηση: running<br/>(ο καλών γίνεται εφεδρικός)"]
alive -- "όχι" --> attempts{"απομένουν προσπάθειες;"}
attempts -- "ναι" --> won2["αποθήκευση attempt + 1, token του καλούντος, νέα μίσθωση<br/>απάντηση: won"]
attempts -- "όχι" --> giveup["σήμανση interrupted<br/>απάντηση: done"]
Όσο η εργασία εκτελείται, ο νικητής στέλνει heartbeat που παρατείνει τη λήξη της μίσθωσης, και στο τέλος σημειώνει την εκτέλεση ως ολοκληρωμένη. Και τα δύο λειτουργούν μόνο με το token της τρέχουσας προσπάθειας.
Το Μισθώσεις καλύπτει ολόκληρο τον μηχανισμό.
stream-id
Ενότητα με τίτλο «stream-id»Κάθε instance προσθέτει μια εγγραφή στο stream της εργασίας με τον χρόνο εκτέλεσης ως entry ID. Το Redis απορρίπτει ένα ID που δεν είναι μεγαλύτερο από το τελευταίο του stream, οπότε μόνο η πρώτη XADD επιτυγχάνει.
A: XADD cron:sync:runs 1791633610000-0 slot ... token a1 -> "1791633610000-0" A runs itB: XADD cron:sync:runs 1791633610000-0 slot ... token b7 -> ERR The ID specified in XADD is equal or smaller than the target stream top itemΕίναι η απλούστερη στρατηγική και απομνημονεύει τις εκτελέσεις για πάντα, επειδή τα IDs μόνο αυξάνονται.
Το Redis 8.6 πρόσθεσε idempotent XADD. Το Redis διατηρεί την πρώτη εγγραφή για ένα κλειδί idempotency και απαντά στις επαναλήψεις με το ID εκείνης της εγγραφής.
A: XADD cron:sync:runs IDMP sync 1791633610000 * slot ... token a1 -> "1791633610012-0" (stored)B: XADD cron:sync:runs IDMP sync 1791633610000 * slot ... token b7 -> "1791633610012-0" (A's entry)Στη συνέχεια, κάθε instance διαβάζει εκείνη την εγγραφή και συγκρίνει τα tokens. Με το ValkeyBackend, το strategy: 'idmp' δεν μεταγλωττίζεται. Με το RedisBackend σε Valkey ή παλαιότερο Redis, η μέθοδος start() αποτυγχάνει με μήνυμα που παραπέμπει στις υπόλοιπες στρατηγικές.
Ρύθμιση του { name: 'idmp' } |
Προεπιλογή | Σημασία |
|---|---|---|
durationSec |
300 |
Για πόσο χρόνο το Redis απομνημονεύει το ID μιας εκτέλεσης (1 έως 86400) |
maxSize |
1000 |
Πόσα IDs εκτελέσεων διατηρεί το Redis ανά εργασία (1 έως 10000) |
new RedisBackend({ strategy: { name: 'idmp', durationSec: 900, maxSize: 5_000 } });Η ίδια συμπεριφορά με το idmp για servers που δεν το υποστηρίζουν. Ένα Lua script σαρώνει τις πρόσφατες εγγραφές του stream για αυτόν τον χρόνο εκτέλεσης και προσθέτει το claim μόνο αν απουσιάζει.
Ρύθμιση του { name: 'script' } |
Προεπιλογή | Σημασία |
|---|---|---|
windowMs |
300000 |
Για πόσο απομνημονεύεται μια δεσμευμένη εκτέλεση. Πρέπει να είναι μεγαλύτερο από το jitterMs + maxLateMs μιας εργασίας |
new ValkeyBackend({ strategy: { name: 'script', windowMs: 10 * 60_000 } });Κλειδιά (Keys)
Ενότητα με τίτλο «Κλειδιά (Keys)»Με τη στρατηγική lease, κάθε εργασία έχει πέντε κλειδιά. Μοιράζονται ένα hash tag (το μέρος μέσα στις αγκύλες), ώστε το Redis Cluster να τα διατηρεί στον ίδιο κόμβο και τα scripts να μπορούν να επεξεργαστούν όλα τους:
| Κλειδί | Τύπος | Περιεχόμενο |
|---|---|---|
{cron:<job>}:state |
hash | Ανά εκτέλεση: attempt, token, status, runner, λήξη μίσθωσης |
{cron:<job>}:active |
set | Εκτελέσεις που δεν έχουν ολοκληρωθεί ακόμα |
{cron:<job>}:slots |
sorted set | Κάθε εκτέλεση στο state, για εκκαθάριση (trim) των παλαιότερων |
{cron:<job>}:runs |
stream | Μία εγγραφή ανά προσπάθεια (ιστορικό) |
{cron:<job>}:results |
sorted set | Ένα αποτέλεσμα ανά προσπάθεια (ιστορικό) |
Με τις στρατηγικές μόνο για claim υπάρχουν τρία:
| Κλειδί | Τύπος | Περιεχόμενο |
|---|---|---|
cron:<job>:runs |
stream | Μία εγγραφή ανά διεκδικηθείσα εκτέλεση |
cron:<job>:manual |
stream | Μία εγγραφή ανά εκτέλεση runNow() |
cron:<job>:results |
sorted set | Ένα αποτέλεσμα ανά εκτέλεση |
Το cron: είναι το prefix. Κάθε στρατηγική γράφει επίσης ένα κλειδί, cron:format: τη μορφή του store, ώστε τα δεδομένα ενός νεότερου anarchon να μη διαβάζονται ποτέ λάθος. Ένα backend αρνείται να ξεκινήσει όταν βρίσκει μορφή νεότερη από όσες διαβάζει (ANARCHON_STORE_FORMAT).
Το ρολόι του server
Ενότητα με τίτλο «Το ρολόι του server»Οι χρόνοι λήξης των μισθώσεων υπολογίζονται με την εντολή TIME του ίδιου του Redis, μέσα στο script. Τα instances δεν συγκρίνουν ποτέ τα ρολόγια τους μεταξύ τους, επομένως μια διαφορά ώρας μεταξύ δύο instances δεν μπορεί να κάνει μια ενεργή μίσθωση να φαίνεται ληγμένη.
Redis Cluster και Sentinel
Ενότητα με τίτλο «Redis Cluster και Sentinel»- Cluster: με τη στρατηγική
leaseόλα τα κλειδιά μιας εργασίας μοιράζονται το ίδιο hash tag, επομένως κάθε script αφορά έναν μοναδικό κόμβο. Περάστε έναν cluster client που δημιουργήσατε εσείς (έναν ioredisClusterή έναν GLIDE cluster client). Οι δοκιμές του ίδιου του anarchon εκτελούνται σε μεμονωμένους servers. - Sentinel και replicas: στοχεύστε το anarchon στον πρωτεύοντα κόμβο (primary). Τα claims είναι εγγραφές (writes).
Το ιστορικό περικόπτεται σε περίπου historySize εκτελέσεις ανά εργασία (προεπιλογή 1000), και βάσει του historyTtlMs εφόσον το ορίσετε. Η κατάσταση μιας εκτέλεσης δεν περικόπτεται ποτέ όσο βρίσκεται σε εξέλιξη, ή όσο ένα καθυστερημένο claim θα μπορούσε να τη ζητήσει.