Bruke Selleri med Django for bakgrunnsoppgavebehandling

Webapplikasjoner starter vanligvis enkelt, men kan bli ganske komplekse, og de fleste av dem overgår raskt ansvaret for bare å svare på HTTP-forespørsler.

Når det skjer, må man skille mellom hva som må skje umiddelbart (vanligvis i HTTP-forespørselslivet) og hva som kan skje til slutt. Hvorfor det? Vel, fordi når søknaden din blir overbelastet med trafikk, gjør enkle ting som dette forskjellen. 

Operasjoner i en webapplikasjon kan klassifiseres som kritisk eller forespørselstidsoperasjoner og bakgrunnsoppgaver, de som skjer utenfor forespørselstid. Disse kartene til de som er beskrevet ovenfor: 

  • må skje umiddelbart: forespørsel-tid operasjoner
  • må skje til slutt: bakgrunnsoppgaver

Forespørselstidsoperasjoner kan gjøres på en enkelt forespørsel / svarssyklus uten å bekymre seg for at operasjonen vil gå ut, eller at brukeren kan ha en dårlig opplevelse. Vanlige eksempler inkluderer CRUD (Opprett, Les, Oppdater, Slett) databaseoperasjoner og brukeradministrasjon (Logg inn / Logg ut rutiner).

Bakgrunnsoppgaver er forskjellige da de vanligvis er ganske tidkrevende og er utsatt for feil, hovedsakelig på grunn av eksterne avhengigheter. Noen vanlige scenarier blant komplekse webapplikasjoner inkluderer:

  • sender bekreftelse eller aktivitets e-post
  • daglig gjennomsøking og skraping av informasjon fra ulike kilder og lagring av dem
  • utfører dataanalyse
  • sletter unødvendige ressurser
  • Eksporterende dokumenter / bilder i ulike formater

Bakgrunnsoppgaver er hovedfokus for denne opplæringen. Det vanligste programmeringsmønsteret som brukes for dette scenariet, er produsentens forbrukerarkitektur. 

Enkelt sagt, kan denne arkitekturen beskrives slik: 

  • Produsenter lager data eller oppgaver.
  • Oppgaver legges inn i en kø som refereres til som oppgavekøen. 
  • Forbrukerne er ansvarlige for at forbruker dataene eller driver oppgavene. 

Vanligvis henter forbrukerne oppgaver fra køen i en første-i-første-ut-modus (FIFO) eller i henhold til deres prioriteringer. Forbrukerne er også referert til som arbeidere, og det er begrepet vi skal bruke hele, da det er i tråd med terminologien som brukes av teknologiene som diskuteres.

Hva slags oppgaver kan behandles i bakgrunnen? Oppgaver som:

  • er ikke avgjørende for den grunnleggende funksjonaliteten til webapplikasjonen
  • kan ikke kjøres i forespørsel / respons syklus siden de er treg (I / O intensiv, etc.)
  • avhenger av eksterne ressurser som kanskje ikke er tilgjengelige eller ikke oppfører seg som forventet
  • Det kan hende at du må prøve på nytt minst en gang
  • må utføres på en tidsplan

Selleri er de facto valget for å gjøre bakgrunnsoppgavebehandling i Python / Django-økosystemet. Den har en enkel og klar API, og den integrerer vakkert med Django. Den støtter ulike teknologier for oppgavekøen og ulike paradigmer for arbeiderne.

I denne opplæringen skal vi lage et Django-leketøy-webprogram (som omhandler virkelige scenarier) som bruker bakgrunnsoppgavebehandling.

Setter ting opp

Forutsatt at du allerede er kjent med Python pakkebehandling og virtuelle miljøer, la oss installere Django:

$ pip installere Django

Jeg har bestemt meg for å bygge enda en blogging-applikasjon. Fokuset på søknaden vil være på enkelhet. En bruker kan ganske enkelt opprette en konto og uten for mye oppstyr kan du lage et innlegg og publisere det på plattformen. 

Sett opp quick_publisher Django-prosjektet:

$ django-admin startproject quick_publisher

La oss få appen startet:

$ cd quick_publisher $ ./manage.py startapp main

Når jeg starter et nytt Django-prosjekt, liker jeg å lage en hoved- Program som inneholder blant annet en egendefinert brukermodell. Oftere enn ikke, støter jeg på begrensninger av standard Django Bruker modell. Å ha en skikk Bruker modellen gir oss fordelen av fleksibilitet.

# main / models.py fra django.db importmodeller fra django.contrib.auth.models importerer AbstractBaseUser, PermissionsMixin, BaseUserManager-klassen UserAccountManager (BaseUserManager): use_in_migrations = True def _create_user (selv, e-post, passord, ** ekstrafelt): hvis ikke e-post: heve ValueError ('Email-adresse må oppgis') hvis ikke passord: oppring ValueError ('Passord må oppgis') email = self.normalize_email (email) user = self.model (email = email, ** extra_fields) user.set_password (passord) user.save (using = self._db) returner bruker def create_user (selv, email = Ingen, passord = Ingen, ** ekstra_felt): returner selv._create_user (email, passord, ** extra_fields) def create_superuser (self, email, passord, ** extra_fields): extra_fields ['is_staff'] = Sann ekstra_fields ['is_superuser'] = Sann tilbakemelding selv._create_user (email, passord, ** extra_fields) klasse Bruker (AbstractBaseUser, PermissionsMixin): REQUIRED_FIELDS = [] USERNAME_FIELD = 'email' objekter = UserAccountManager () email = models.EmailField ('e-post', unikt = True, blank = False, null = False) full_name = models.CharField ('fullt navn', blank = True, null = True, max_length = 400) is_staff = models.BooleanField , default = False) is_active = models.BooleanField ('aktiv', standard = True) def get_short_name (selv): return self.email def get_full_name (selv): return self.email def __unicode __ (selv): returner self.email

Sørg for å sjekke ut Django-dokumentasjonen hvis du ikke er kjent med hvordan egendefinerte brukermodeller fungerer.

Nå må vi fortelle Django å bruke denne brukermodellen i stedet for den vanlige. Legg denne linjen til quick_publisher / settings.py fil:

AUTH_USER_MODEL = 'main.User' 

Vi må også legge til hoved- søknad til INSTALLED_APPS liste i quick_publisher / settings.py fil. Vi kan nå opprette migreringer, bruke dem og opprette en superbruker for å kunne logge inn på Django admin panel:

$ ./manage.py makemigrations hoved $ ./manage.py migrere $ ./manage.py createsuperuser

La oss nå lage en egen Django-applikasjon som er ansvarlig for innlegg:

$ ./manage.py startapp publisering

La oss definere en enkel Post-modell i utgiver / models.py:

fra django.db importmodeller fra django.utils importere tidszone fra django.contrib.auth importere get_user_model klasse Post (models.Model): author = models.ForeignKey (get_user_model ()) created = models.DateTimeField ('Opprettet dato', standard = timezone.now) title = models.CharField ('Tittel', max_length = 200) content = models.TextField ('Innhold') slug = models.SlugField ('Slug') def __str __ (selv): return "av% s '% (self.title, self.author)

Hooking Post modell med Django admin er ferdig i utgiver / admin.py filen som denne:

fra django.contrib import admin fra .models import Post @ admin.register (Post) klasse PostAdmin (admin.ModelAdmin): pass

Til slutt, la oss kroke forlegger søknad med vårt prosjekt ved å legge det til INSTALLED_APPS liste.

Vi kan nå kjøre serveren og gå over til http: // localhost: 8000 / admin / og opprett våre første innlegg slik at vi har noe å leke med:

$ ./manage.py runserver

Jeg stoler på at du har gjort leksene dine, og du har opprettet innleggene. 

La oss gå videre. Det neste åpenbare skrittet er å skape en måte å vise publiserte innlegg på. 

# publisher / views.py fra django.http import Http404 fra django.shortcuts import gjengi fra .models import Post def view_post (forespørsel, slug): prøv: post = Post.objects.get (slug = slug) unntatt Post.DoesNotExist: heve Http404 ("Poll eksisterer ikke") returnere gjengivelse (forespørsel, 'post.html', context = ('post': post)

La oss knytte vår nye visning med en URL i: quick_publisher / urls.py

# quick_publisher / urls.py fra django.conf.urls import url fra django.contrib import admin fra publisher.views import view_post urlpatterns = [url (r '^ admin /', admin.site.urls), url (r '^ (? P[a-zA-Z0-9 \ -] +) ', view_post, name = "view_post")]

Til slutt, la oss lage malen som gjør innlegget i: utgiver / templates / post.html

       

post.title

post.content

Publisert av post.author.full_name på post.created

Vi kan nå gå til http: // localhost: 8000 / slug-of-the-post-you-created / i nettleseren. Det er ikke akkurat et mirakel av webdesign, men å lage flotte innlegg er utenfor omfanget av denne opplæringen.

Sende bekreftelses e-post

Her er det klassiske scenariet:

  • Du oppretter en konto på en plattform.
  • Du oppgir en e-postadresse som skal identifiseres unikt på plattformen.
  • Plattformen sjekker at du faktisk er eieren av e-postadressen ved å sende en epost med en bekreftelseslink.
  • Inntil du utfører verifiseringen, kan du ikke (fullt) bruke plattformen.

La oss legge til en is_verified flagg og verification_uuid på Bruker modell:

# main / models.py import uuid class Bruker (AbstractBaseUser, PermissionsMixin): REQUIRED_FIELDS = [] USERNAME_FIELD = 'email' objekter = UserAccountManager () email = models.EmailField ('email', unikt = True, blank = False, null = False) full_name = models.CharField ('fullt navn', blank = True, null = True, max_length = 400) is_staff = models.BooleanField ('stabsstatus', default = False) is_active = models.BooleanField ('aktiv' default = True) is_verified = models.BooleanField ('verifisert', standard = False) # Legg til 'is_verified' flagg verification_uuid = models.UUIDField ('Unik verifisering UUID', default = uuid.uuid4) def get_short_name self.email def get_full_name (selv): return self.email def __unicode __ (selv): returner self.email

La oss bruke denne anledningen til å legge til brukermodellen til administratoren:

fra django.contrib import admin fra .models import Bruker @ admin.register (User) class UserAdmin (admin.ModelAdmin): pass

La oss gjøre endringene gjenspeilet i databasen:

$ ./manage.py makemigrations $ ./manage.py migrere

Vi må nå skrive et stykke kode som sender en e-post når en brukereksempel er opprettet. Dette er hva Django-signaler er for, og dette er en perfekt anledning til å berøre dette emnet. 

Signaler blir sparket før / etter at visse hendelser oppstår i søknaden. Vi kan definere tilbakeringingsfunksjoner som utløses automatisk når signalene blir sparket. For å lage en tilbakeringingsutløseren må vi først koble den til et signal.

Vi skal lage et tilbakering som vil bli utløst etter at en brukermodell er opprettet. Vi legger til denne koden etter Bruker modelldefinisjon i: Hoved / models.py

fra django.db.models importere signaler fra django.core.mail import send_mail def user_post_save (sender, forekomst, signal, * args, ** kwargs): hvis ikke instance.is_verified: # Send verifikasjons-epost send_mail ('Bekreft QuickPublisher-kontoen din ',' Følg denne lenken for å bekrefte kontoen din: 'http: // localhost: 8000% s'% reverse ('verifiser', kwargs = 'uuid': str (instance.verification_uuid)), 'fra @ quickpublisher. dev ', [instance.email], fail_silently = False,) signals.post_save.connect (user_post_save, sender = bruker)

Det vi har gjort her er, vi har definert a user_post_save funksjon og tilkoblet den til post_save signal (en som utløses etter at en modell er lagret) sendt av Bruker modell.

Django sender ikke bare e-post ut på egen hånd; det må knyttes til en e-posttjeneste. For enkelhets skyld kan du legge til Gmail-legitimasjonene dine i quick_publisher / settings.py, eller du kan legge til din favoritt e-postleverandør. 

Her ser du hvordan Gmail-konfigurasjonen ser ut:

EMAIL_USE_TLS = EMAIL_HOST = 'smtp.gmail.com' EMAIL_HOST_USER = '@ gmail.com 'EMAIL_HOST_PASSWORD =''EMAIL_PORT = 587

For å teste ut ting, gå inn på administrasjonspanelet og opprett en ny bruker med en gyldig e-postadresse du raskt kan sjekke. Hvis alt gikk bra, vil du motta en e-post med en bekreftelseskobling. Verifikasjonsrutinen er ikke klar ennå. 

Slik bekrefter du kontoen:

# main / views.py fra django.http import Http404 fra django.shortcuts import render, omdirigere fra .models import Bruker def home (request): return render (request, 'home.html') def bekrefte (forespørsel, uuid): Prøv: user = User.objects.get (verification_uuid = uuid, is_verified = False) unntatt User.DoesNotExist: heve Http404 ("Brukeren eksisterer ikke eller er allerede bekreftet") user.is_verified = Ekte user.save () returnere omdirigering () 'hjem')

Koble utsikten opp i: quick_publisher / urls.py

# quick_publisher / urls.py fra django.conf.urls import url fra django.contrib import admin fra publisher.views import view_post fra main.views importere hjem, bekreft urlpatterns = [url (r '^ $', hjem, navn = " hjemme "), url (r '^ admin /', admin.site.urls), url (r '^ verifiser / (P[a-z0-9 \ -] +) / ', verifiser, navn = "verifiser"), url (r' ^ (P[a-zA-Z0-9 \ -] +) ', view_post, name = "view_post")]

Husk også å opprette en home.html filen under Hoved / templates / home.html. Det vil bli gjengitt av hjem utsikt.

Prøv å kjøre hele scenariet igjen. Hvis alt er bra, vil du motta en e-post med en gyldig bekreftelsesadresse. Hvis du følger nettadressen og deretter sjekker inn administrasjonen, kan du se hvordan kontoen er verifisert.

Sende e-post Asynkront

Her er problemet med det vi har gjort hittil. Du har kanskje lagt merke til at det å opprette en bruker er litt treg. Det er fordi Django sender verifikasjonsmeldingen innen forespørselstidspunktet. 

Slik fungerer det: Vi sender brukerdata til Django-applikasjonen. Programmet oppretter en Bruker modell og oppretter deretter en forbindelse til Gmail (eller en annen tjeneste du har valgt). Django venter på svaret, og bare da returnerer det et svar til nettleseren vår. 

Her er hvor Selleri kommer inn. Først må du kontrollere at det er installert:

$ pip installere Selleri

Vi trenger nå å lage et Selleri-program i vår Django-applikasjon:

# quick_publisher / celery.py import oss fra selleri import Selder os.environ.setdefault ('DJANGO_SETTINGS_MODULE', 'quick_publisher.settings') app = Selleri ('quick_publisher') app.config_from_object ('django.conf: settings') # Last oppgavemoduler fra alle registrerte Django app konfigs. app.autodiscover_tasks ()

Selleri er en oppgavekø. Den mottar oppgaver fra vår Django-applikasjon, og den vil kjøre dem i bakgrunnen. Selleri må paires med andre tjenester som fungerer som meglere. 

Meglere mellom sending av meldinger mellom webapplikasjon og Selleri. I denne opplæringen bruker vi Redis. Redis er enkel å installere, og vi kan lett komme i gang med det uten for mye oppstyr.

Du kan installere Redis ved å følge instruksjonene på Redis hurtigstartside. Du må installere Redis Python biblioteket, pip installere redis, og bunken som er nødvendig for bruk av Redis og Selleri: pip installere selleri [redis].

Start Redis-serveren i en separat konsoll som denne: $ redis-server

La oss legge til Celery / Redis-relaterte configs i quick_publisher / settings.py:

# REDIS relaterte innstillinger REDIS_HOST = 'localhost' REDIS_PORT = '6379' BROKER_URL = 'redis: //' + REDIS_HOST + ':' + REDIS_PORT + '/ 0' BROKER_TRANSPORT_OPTIONS = 'visibility_timeout': 3600 CELERY_RESULT_BACKEND = 'redis: / / '+ REDIS_HOST +': '+ REDIS_PORT +' / 0 '

Før alt kan kjøres i Selleri, må det deklareres som en oppgave. 

Slik gjør du dette:

# main / tasks.py import logging fra django.urls importere omvendt fra django.core.mail import send_mail fra django.contrib.auth import get_user_model fra quick_publisher.celery import app @ app.task def send_verification_email (user_id): UserModel = get_user_model ( ) Prøv: user = UserModel.objects.get (pk = user_id) send_mail ('Bekreft QuickPublisher-kontoen din', 'Følg denne lenken for å bekrefte kontoen din: http: // localhost: 8000% s'% reverse , Kwargs = 'uuid': str (user.verification_uuid)), '[email protected]', [user.email], fail_silently = False,) unntatt UserModel.DoesNotExist: logging.warning ("Forsøkte å sende verifisering e-post til ikke-eksisterende bruker '% s' "% user_id)

Det vi har gjort her er dette: Vi flyttet sendingsbekreftelses-e-postfunksjonen i en annen fil som heter tasks.py

Noen få notater:

  • Navnet på filen er viktig. Selleri går gjennom alle appene i INSTALLED_APPS og registrerer oppgavene i tasks.py filer.
  • Legg merke til hvordan vi dekorerte send_verification_email fungere med @ app.task. Dette forteller Selleri Dette er en oppgave som skal kjøres i oppgavekøen.
  • Legg merke til hvordan vi forventer som argument bruker-ID snarere enn a Bruker gjenstand. Dette skyldes at vi kan ha problemer med å seriere komplekse objekter når du sender oppgavene til Selleri. Det er best å holde dem enkle.

Kommer tilbake til Hoved / models.py, signalkoden blir til:

fra django.db.models importere signaler fra main.tasks import send_verification_email def user_post_save (sender, forekomst, signal, * args, ** kwargs): hvis ikke instance.is_verified: # Send verifiserings-epost send_verification_email.delay (instance.pk) signaler .post_save.connect (user_post_save, sender = bruker)

Legg merke til hvordan vi kaller .utsette metode på oppgaveobjektet. Dette betyr at vi sender oppgaven av til Selleri, og vi venter ikke på resultatet. Hvis vi brukte send_verification_email (instance.pk) I stedet vil vi fortsatt sende det til Selleri, men vil vente på oppgaven å fullføre, noe som ikke er det vi ønsker.

Før du begynner å lage en ny bruker, er det en fangst. Selleri er en tjeneste, og vi må starte det. Åpne en ny konsoll, pass på at du aktiverer riktig virtualenv, og naviger til prosjektmappen.

$ selleri-en quick_publisher --loglevel = debug --concurrency = 4

Dette starter fire selleri prosess arbeidere. Ja, nå kan du endelig gå og skape en annen bruker. Legg merke til hvordan det ikke er forsinkelser, og sørg for å se loggene i selgerkonsollen og se om oppgavene er riktig utført. Dette skulle se slik ut:

[2017-04-28 15: 00: 09,190: DEBUG / MainProcess] Oppgave akseptert: main.tasks.send_verification_email [f1f41e1f-ca39-43d2-a37d-9de085dc99de] pid: 62065 [2017-04-28 15: 00: 11,740: INFO / PoolWorker-2] Oppgave main.tasks.send_verification_email [f1f41e1f-ca39-43d2-a37d-9de085dc99de] lyktes i 2.5500912349671125s: Ingen

Periodiske oppgaver med selleri

Her er et annet vanlig scenario. De fleste modne webapplikasjoner sender brukerne livscyklusmeldinger for å holde dem engasjert. Noen vanlige eksempler på livssyklus e-post:

  • månedlige rapporter
  • aktivitetsvarsler (liker, vennskapsforespørsler, etc.)
  • påminnelser for å utføre visse handlinger ("Ikke glem å aktivere kontoen din")

Her er hva vi skal gjøre i vår app. Vi skal telle hvor mange ganger hvert innlegg har blitt sett og sende en daglig rapport til forfatteren. En gang hver eneste dag skal vi gå gjennom alle brukerne, hente innleggene sine og sende en epost med et bord som inneholder innleggene og vise teller.

La oss endre Post modell slik at vi kan imøtekomme synsfelt scenariet.

klasse Post (models.Model): author = models.ForeignKey (User) created = models.DateTimeField ('Opprettet dato', default = timezone.now) title = models.CharField ('Tittel', max_length = 200) innhold = modeller .TextField ('Innhold') slug = models.SlugField ('Slug') view_count = models.IntegerField ("Vis antall", standard = 0) def __str __ (selv): returner% s '% self.title, self.author)

Som alltid, når vi endrer en modell, må vi migrere databasen:

$ ./manage.py makemigrations $ ./manage.py migrere

La oss også endre view_post Django-visning for å telle visninger:

def view_post (request, slug): prøv: post = Post.objects.get (slug = slug) unntatt Post.DoesNotExist: raise Http404 ("Poll eksisterer ikke") post.view_count + = 1 post.save () return render (forespørsel, 'post.html', context = ('post': post)

Det ville være nyttig å vise seertall i malen. Legg til dette 

Sett post.view_count ganger

 et sted inne i utgiver / templates / post.html fil. Gjør et par visninger på et innlegg nå og se hvordan disken øker.

La oss lage en Selleri-oppgave. Siden det handler om innlegg, skal jeg legge den inn utgiver / tasks.py:

fra django.template import Mal, Kontekst fra django.core.mail import send_mail fra django.contrib.auth import get_user_model fra quick_publisher.celery import app fra publisher.models import Post REPORT_TEMPLATE = "" "Slik har du gjort nå: % for innlegg i innlegg% "post.title": sett post.view_count ganger | % endfor% "" "@ app.task def send_view_count_report (): for bruker i get_user_model (). objects.all (): posts = Post.objects.filter (forfatter = bruker) hvis ikke innlegg: fortsett template = Template (REPORT_TEMPLATE) send_mail ('Din QuickPublisher Aktivitet', template.render (context = Context ('posts' innlegg), '[email protected]', [user.email], fail_silently = False,)

Hver gang du gjør endringer i Selleri-oppgaver, husk å gjenoppta Selleri-prosessen. Selleri må oppdage og omlaste oppgaver. Før du oppretter en periodisk oppgave, bør vi teste dette ut i Django-skallet for å sikre at alt fungerer som ønsket:

$ ./manage.py shell i [1]: fra publisher.tasks importerer send_view_count_report I [2]: send_view_count_report.delay ()

Forhåpentligvis mottok du en fin liten rapport i e-posten din. 

La oss nå lage en periodisk oppgave. Åpne opp quick_publisher / celery.py og registrer de periodiske oppgavene:

# quick_publisher / celery.py import oss fra selleri import Selleri fra selleri.schemaer importere crontab os.environ.setdefault ('DJANGO_SETTINGS_MODULE', 'quick_publisher.settings') app = Selleri ('quick_publisher') app.config_from_object ('django.conf : innstillinger ') # Last opp oppgavemoduler fra alle registrerte Django app konfigs. app.autodiscover_tasks () app.conf.beat_schedule = 'send-report-every-single-minute': 'oppgave': 'publisher.tasks.send_view_count_report', 'schedule': crontab (), # endre til 'crontab (minutt = 0, time = 0) 'hvis du vil at den skal løpe daglig om midnatt,

Så langt har vi opprettet en tidsplan som skulle løpe oppgaven publisher.tasks.send_view_count_report hvert minutt som angitt av crontab () notasjon. Du kan også angi forskjellige Celery Crontab-tidsplaner. 

Åpne en annen konsoll, aktiver det riktige miljøet, og start Celery Beat-tjenesten. 

$ selleri-en quick_publisher slå

Beat-tjenesten er å skape oppgaver i Selleri i henhold til tidsplanen. Ta hensyn til at timeplanen gjør send_view_count_report Oppgave løp hvert minutt i henhold til oppsettet. Det er bra for testing, men ikke anbefalt for en ekteverden webapplikasjon.

Å gjøre oppgaver mer pålitelige

Oppgaver blir ofte brukt til å utføre upålitelige operasjoner, operasjoner som er avhengige av eksterne ressurser eller som lett kan mislykkes på grunn av ulike årsaker. Her er en veiledning for å gjøre dem mer pålitelige:

  • Gjør oppgaver idempotent. En idempotent oppgave er en oppgave som, hvis stoppet midtveis, ikke endrer systemets tilstand på noen måte. Oppgaven gjør enten full endringer i systemet eller ingen i det hele tatt.
  • Prøv oppgavene på nytt. Hvis oppgaven feiler, er det en god ide å prøve den igjen og igjen til den blir fullført. Du kan gjøre dette i Selleri med Selleri Retry. En annen interessant ting å se på er eksponentiell Backoff-algoritmen. Dette kan komme til nytte når du tenker på å begrense unødvendig belastning på serveren fra gjengitte oppgaver.

konklusjoner

Jeg håper dette har vært en interessant opplæring for deg og en god introduksjon til bruk av Selleri med Django. 

Her er noen konklusjoner vi kan tegne:

  • Det er god praksis å holde upålitelige og tidkrevende oppgaver utenfor forespørselstiden.
  • Langtidsoppgaver bør utføres i bakgrunnen ved arbeidsprosesser (eller andre paradigmer).
  • Bakgrunnsoppgaver kan brukes til ulike oppgaver som ikke er kritiske for programmets grunnleggende funksjon.
  • Selleri kan også takle periodiske oppgaver ved hjelp av selleri beat service.
  • Oppgaver kan være mer pålitelige hvis de blir idempotente og forsøkt (kanskje bruker eksponentiell backoff).