>_ DevTrendsnl

Taal

Home

Talen

Secties

Frontend Backend Mobiel DevOps AI / ML GameDev Blockchain Embedded Beveiliging
Python

Taken plannen in Python zonder Celery en workarounds

Iedere backend-ontwikkelaar heeft hier waarschijnlijk mee te maken gehad. Je bouwt een webservice met FastAPI of Flask, het project is nog klein en draait op één server. Dan vraagt de productmanager: "Laten we klanten elke ochtend om 9 uur een samenvatting sturen, en elke uur verlopen winkelwagentjes resetten?"

De eerste instinct is om Celery met Celery Beat en Redis eraan te koppelen. Maar een broker opzetten, workers configureren en daemons monitoren voor slechts twee achtergrondtaken voelt overdreven aan. De tweede optie is systeem-cron, maar dat verspreidt logica over applicatiecode en serverconfiguratie. Je wilt de planner ingebed in je code, capable of handling asyncio, en schaalbaar over meerdere nodes wanneer nodig.

Dit is waar de APScheduler (Advanced Python Scheduler) bibliotheek van pas komt.

Wat de bibliotheek kan doen

APScheduler bestaat al een tijdje en het project is momenteel in transitie naar versie 4.0. De vierde branch is nog in pre-release status, maar heeft de architectuur van de bibliotheek aanzienlijk herstructureerd.

Voorheen was het voornamelijk een lokale planner voor één proces, maar nu is het uitgegroeid tot een volwaardig gedistribueerd queue- en planningssysteem. Het eenvoudigste gebruik draait nog steeds in slechts drie regels code.

Het kernconcept: je declareert reguliere Python-functies of coroutines en koppelt een trigger met de noodzakelijke uitvoeringsvoorwaarden.

from apscheduler.schedulers.asyncio import AsyncIOScheduler

scheduler = AsyncIOScheduler()

async def send_digest():
    print("Отправляем утренний дайджест...")

# Запуск каждый будний день в 9 утра
scheduler.add_job(send_digest, 'cron', day_of_week='mon-fri', hour=9, minute=0)
scheduler.start()

De bibliotheek houdt tijd bij, berekent offsets en roept functies aan op het juiste moment.

Planningsopties

Er zijn vier ingebouwde triggertypen beschikbaar:

  • Cron trigger. Vertrouwde Linux-stijl syntaxis. Je kunt flexibel weekdagen, maanden, specifieke uren en minuten instellen.
  • Intervallen. Draai elke N seconden, minuten of uren. Nuttig voor regelmatig pollen van externe API's.
  • Kalender trigger. Nodig wanneer het interval afhangt van de lengte van een maand of jaar. Bijvoorbeeld, voer een taak strikt uit op de eerste dag van elke maand om 12 uur 's middags.
  • Eenmalige uitvoering. Vuurt exact één keer af op een opgegeven toekomstige datum en tijd.

Als de ingebouwde voorwaarden niet voldoende zijn, kunnen triggers worden gecombineerd met samengestelde regels of kun je je eigen klasse schrijven met aangepaste logica.

Bescherming tegen veelvoorkomende fouten

In de praktijk komen achtergrondtaken regelmatig overbelasting en vertragingen tegen. APScheduler bevat verschillende nuttige mechanismen die vaak over het hoofd worden gezien in aangepaste oplossingen gebouwd op while True en sleep.

Ten eerste, het beperken van gelijktijdige uitvoeringen. Als je een zware rapportexport elke vijf minuten hebt geconfigureerd, maar de vorige uitvoering zeven minuten is vastgelopen, zal de planner geen tweede exemplaar parallel starten en de database niet overbelasten.

Ten tweede, de jitter parameter. Het voegt een willekeurige vertraging toe aan de starttijd van de taak. Stel je voor dat je honderd workers hebt en ze moeten allemaal de cache vernieuwen om precies 00:00. Zonder jitter zal de database een directe piekbelasting ontvangen. Met een willekeurige offset van een paar seconden wordt de belasting gelijkmatig verdeeld.

Ten derde, misfire grace time handling. Als de server bevroor onder belasting of opnieuw opstartte, controleert de planner hoe laat de taak is. Als de vertraging binnen de acceptabele limiet past, wordt de taak uitgevoerd; zo niet, wordt deze overgeslagen zonder queue-opbouw.

Opslag en gedistribueerde modus

Voor eenvoudige scripts kunnen taken in het geheugen worden bewaard. Maar als de service opnieuw opstart, wordt het schema gereset. Om dit te voorkomen ondersteunt de bibliotheek persistente opslag:

  • PostgreSQL
  • MySQL
  • SQLite
  • MongoDB

In versie vier leerde de planner werken in een gedistribueerd cluster. Meerdere applicatie-instanties maken verbinding met een gedeelde database en event broker (Redis, PostgreSQL LISTEN/NOTIFY en MQTT worden ondersteund).

Dit bereikt horizontale schaling: één node valt uit, de anderen pikken taken uit de queue op.

# Пример концепции работы с постоянным хранилищем
from apscheduler.schedulers.asyncio import AsyncIOScheduler
from apscheduler.jobstores.sqlalchemy import SQLAlchemyJobStore

jobstores = {
    'default': SQLAlchemyJobStore(url='postgresql+asyncpg://user:pass@localhost/mydb')
}

scheduler = AsyncIOScheduler(jobstores=jobstores)

Synchrone en asynchrone code

De bibliotheek past goed in de moderne Python-stack. Er zijn verschillende planner-implementaties beschikbaar:

  • AsyncIOScheduler en integratie met Trio voor moderne async backends zoals FastAPI, Litestar of Aiohttp.
  • BackgroundScheduler en BlockingScheduler voor synchrone scripts, Django en Flask.

Je hoeft async-functies niet in synchrone workarounds te wrappen met asyncio.run() — de planner wacht coroutines standaard af binnen de main event loop.

Waar dit van pas komt

Ik gebruik APScheduler meestal in drie typische situaties:

  1. Kleine microservices en bots. Wanneer het implementeren van Celery of RQ overdreven zou zijn en periodieke taken direct binnen het proces nodig zijn.
  2. Uitgestelde gebruikersacties. Bijvoorbeeld, stuur een e-mail om te vragen om een bestelling te beoordelen exact 24 uur na levering.
  3. Tijdelijke data opruimen en periodieke synchronisatie van referentiegegevens uit externe systemen.

Is het de moeite waard om in een project te gebruiken

Als je in Python schrijft en voorspelbare tijdgebaseerde taakuitvoering nodig hebt, is APScheduler een van de meest volwassen opties.

Het enige nuancepunt op dit moment: de overgangsperiode tussen versies 3.x en 4.0. De derde branch is jarenlang in productie getest, is maximaal stabiel, maar heeft beperkingen in gedistribueerde werking. Versie 4.0 brengt moderne architectuur en schaling, maar de auteur waarschuwt eerlijk voor mogelijke breaking API-wijzigingen vóór de definitieve release.

Voor huidige productie is het veiliger om bij de stabiele 3.x branch te blijven en versie 4.0 is de moeite waard om te proberen in pet projects of nieuwe microservices, terwijl je de aankomende wijzigingen in de gaten houdt.

Gerelateerde projecten