Како паузирати и контролисати редове чекања у Ларавелу корак по корак

Последње ажурирање: КСНУМКС децембра КСНУМКС
  • Ларавел нуди обједињени API за редове чекања са више драјвера (база података, Redis, SQS…) и раздвајањем између конекција и логичких редова чекања.
  • Послови омогућавају да се захтевни задаци преместе у позадину, уз подршку за серијализацију модела, посреднички софтвер, једнократне послове, шифровање, пакете и низове.
  • Радницима се управља помоћу queue:work, Supervisor и команди као што су queue:pause/queue:continue, контролишући поновне покушаје, временска ограничења и приоритете.
  • Постоји комплетан екосистем за кварове, праћење и тестирање (failed_jobs, queue:retry, queue:monitor, Queue::fake) који чини редове поузданим у продукцији.

Управљање редовима у Ларавелу

Рад са редовима чекања у Laravel-у је готово обавезан у сваком озбиљном пројекту: слање имејлова, обрада CSV датотека, генерисање PDF-ова, промена величине слика, позивање екстерних API-ја… Ако се све то уради у главном HTTP захтеву, веб-сајт постаје спор, појављује се 500 грешака, а корисник на крају очајнички гледа у празан екран.

Добра вест је да Laravel нуди моћну и флексибилну инфраструктуру чекања која вам омогућава да делегирате тешке послове позадинским процесима, управљате њима по приоритету, групишете их у групе, пратите их, поново покушавате када не успеју, па чак и привремено паузирате процесе ради одржавања. Хајде да пажљиво погледамо (и ништа не изоставимо) како да извучемо максимум из тога, укључујући како да паузирате, наставите и контролишете његово понашање у продукцији.

Основни концепти: везе, редови чекања и драјвери

У Ларавелу, пре него што било шта паузирате, морате разумети разлику између везе редова и сами редови. у config/queue.php имате низ connections где дефинишете сваки бекенд: база података, redis, beanstalkd, sqs, синхронизација, null, пребацивање на резервни систем, rabbitmq (ако га додате), итд.

Свака веза може имати неколико логички редови (имена као што су default, emails, high, low, importsАтрибут queue Свака веза означава који је подразумевани ред у који ће се послови упућивати ако није наведено ништа друго. onQueue()На овај начин можете да урадите ствари као што су:

  • Брзи ред за имејлове или кратке трансакције.
  • Још један низак приоритет за дуготрајне задатке као што су обрада видео записа или великих извештаја.
  • Редови сегментирани по типу задатка: imports, notificaciones, reportes, Итд

Када покренете радника са php artisan queue:workПодразумевано, слуша ред наведен као Уобичајено на изабраној вези. Ако желите да дате приоритет, можете проследити више редова одвојених зарезима:

php artisan queue:work redis --queue=high,default,low

На овај начин, радник прво обрађује high , затим default , и тек онда low , што је кључно када је систем оптерећен и не желите да извештај од 30 минута блокира имејлове високог приоритета.

Драјвери реда и предуслови

Ларавел нуди обједињени API за неколико драјвера реда , али сваки има своје специфичне карактеристике и зависности. Избор правог драјвера је кључан пре него што се разговара о паузирању воркера.

База података возача

Возач база података Чува послове у SQL табели (обично jobsЛако се подешава и савршено је за мале пројекте или развојна окружења где не желите да се петљате са Redis-ом или SQS-ом.

Основни кораци:

  • Генеришите миграцију: php artisan queue:table (или у новијим верзијама, долази као create_jobs_table Уобичајено).
  • Покрените миграције: php artisan migrate.
  • Цонфигуре QUEUE_CONNECTION=база података у .env и потврди у config/queue.php да 'default' => env('QUEUE_CONNECTION','database').

Довољно је згодно и робусно, али са много редова чекања и пуно саобраћаја може постати уско грло , јер све пролази кроз исту релациону базу података.

Драјвер Редис

Redis драјвер је стандардни радни коњ у продукцији. Брз је, подржава напредне функције (закључавање, ограничавање брзине, атомске браве, Horizon итд.) и веома добро се скалира.

Važne tačke:

  • Потребно је да конфигуришете Redis везу у config/database.php.
  • Опције serializer y compression из Редиса Нису компатибилни са возачем реда.
  • Ако користиш Редис ЦлустерИмена редова морају имати хештег, на пример {default}тако да сви кључеви у том реду падну у исти слот.
  • Опција block_for Омогућава раднику да блокира док чека на послове неколико секунди, уместо континуираног испитивања: штеди процесор и смањује упите ка Redis серверу.

На пример:

'redis' => ,

Ако ставите блок_за = 0Радник остаје блокиран на неодређено време док се посао не ослободи, што треба имати на уму ако желите да брзо реагује на сигнале попут SIGTERM или команде за паузирање.

Остали драјвери: SQS, Beanstalkd, null, failover…

Поред база података и redi-а, Laravel подржава и друге системе :

  • Амазон СКСУправљани редови чекања на AWS-у, са подршком за ФИФОГрупе порука, дедупликација и напредна подешавања видљивости. Потребан је SDK. aws/aws-sdk-php.
  • Стабљика пасуљаВеома брзо и једноставно, користећи пакет pda/pheanstalk.
  • синхронизацију: обавља задатке одмах у истом процесу. Корисно у развоју или тестирању, али у продукцији је практично као да се редови уопште не користе.
  • нула: Одбацује задатке чим буду „отпремљени“. Користи се за потпуно онемогућавање система чекања.
  • prelazak na greškuОво вам омогућава да конфигуришете више веза, а ако примарна не успе, Laravel покушава да пребаци задатак на следећу на листи. Идеално за окружења где висока доступност је критичан.
  Дизајн софтвера: фазе, архитектура и најбоље праксе

На нивоу паузирања и настављања рада радника, логика је практично иста без обзира на драјвер, јер се њоме управља из Artisan команди и класе Worker , а не из позадине реда чекања.

Креирање послова и серијализација модела

Un посао У Ларавелу, то је једноставно класа која обухвата задатак који треба да се изврши у реду чекања. Обично се генерише помоћу Артисана и чува у app/Jobs.

Да бисте га направили:

php artisan make:job ProcessPodcast

Генерисана класа спроводи ShouldQueue и обично користи особине Dispatchable, InteractsWithQueue, Queueable y SerializesModelsСрце је у методи handle()што је оно што радник ради када посао стигне.

Посебно моћна карактеристика је аутоматска серијализација Eloquent модела . Ако прихватите модел у конструктору посла (Job), Laravel не додаје цео објекат у ред чекања, већ само његов идентификатор. Када се посао обради, реконструише модел из базе података са учитаним релацијама.

Типичан пример (у псеудокоду, да би се избегло дословно понављање):

  • Градитељ прима Подкаст $podcast.
  • Особина SerializesModels Одговоран је за чување ИД-а.
  • En handle(AudioProcessor $processor) Ви обављате тежак посао (обрада звука, на пример).

Ако не желите да се односи у моделу серијализују (тако да корисни терет не буде огроман), можете користити $model->withoutRelations() или у PHP 8 атрибут # на имању које је промовисао градитељ.

Убризгавање зависности у методу handle-а

Још једна предност је што можете убризгајте сервисе директно у методу handle-а (као да је контролер), јер Laravel такође користи контејнер сервиса у Jobs-у. На пример, можете захтевати AudioProcessorHTTP клијенти, репозиторијуми итд., а фрејмворк се брине о њиховом решавању.

Ако вам је потребна ултра-фина контрола онога што се назива handleможете користити Container::bindMethod() код добављача услуга и сами дефинишите логику убризгавања, али у већини случајева нема потребе толико компликовати ствари.

Посреднички софтвер за послове

Баш као што руте имају посреднички софтвер, тако и послови могу имати специфични посреднички софтвер који се извршавају пре и после посла. Ово значајно смањује понављајући код у методама handle() и посебно је корисно за:

  • Ограничавање брзине са Редисом.
  • избегавати преклапања радова који се дотичу истог ресурса.
  • Редовни изузеци за нестабилне API-је.
  • Прескакање послова под одређеним условима (Skip посреднички софтвер).

Мидлвер се обично поставља у app/Jobs/Middleware и враћају се из методе middleware() Из књиге Јова. Концептуални пример:

public function middleware(): array { return ;

Посебне врсте послова: јединствени, шифровани и закључани

Ларавел вам омогућава да означите одређене послове као јединствен како би се осигурало да се ниједна два идентична случаја никада не ставе у ред чекања истовремено. То се постиже имплементацијом интерфејса ShouldBeUnique o ShouldBeUniqueUntilProcessingи подржава дефинисање кључа uniqueId() и време uniqueFor.

Ово је идеално за ствари као што су:

  • Поново израчунајте индекс претраге производа: само једном по производу док се не заврши.
  • Синхронизације са спољним сервисима који не дозвољавају истовремене захтеве за исти ресурс.

Испод, Laravel користи атомска брава кеша (Redis, memcached, база података итд.). Такође можете изабрати драјвер кеша за ту браву помоћу uniqueVia().

Поред тога, ту је и интерфејс ShouldBeEncrypted, чиме назначавате да је комплетан посао Унесите свој код пре него што уђете у редВеома корисно када се преносе осетљиви подаци, а не желите да путују у обичном тексту кроз Redis, SQS или базу података.

Отпремајте, одлажите и извршавајте послове у различитим режимима

Када је ваш посао дефинисан, покрећете га са Job::dispatch() од контролера, слушача догађаја, Artisan команди или чак затварања. Параметри које прослеђујете dispatch Они иду директно градитељу Јова.

Занимљиве варијације:

  • dispatchIf() y dispatchUnless() да услови пошиљку у једном реду.
  • delay() тако да се посао не може обрадити до одређеног датума/времена.
  • dispatchAfterResponse() o afterResponse() en dispatch() Затварања, која одлажу извршење док се не пошаље HTTP одговор, али унутар истог PHP процеса.
  • dispatchSync() да се посао покрене синхроно (без проласка кроз ред чекања), али поново користећи исту класу.
  • Специјалне везе као што су deferred o background извршити након одговора, у истом процесу или у новом PHP процесу.

Коначно, можете одредити везу и ред чекања помоћу уланчаних метода onConnection() y onQueue(), било приликом отпреме или у оквиру креатора послова.

Фина контрола: поновни покушаји, одлагање, временски истеци и руковање грешкама

Велики део рада са редовима чекања у Ларавелу је одлучивање колико пута поново покушати задатак , колико дуго чекати између покушаја и када га сматрати неуспехом.

  Реплит: Све што треба да знате о овом алату за сарадњу

Доступне опције:

  • --tries en queue:work да подесите максималан број покушаја за све послове тог радника (осим ако посао не дефинише свој) $tries o tries()).
  • $tries или метод tries() у класи Job за контролу по задатку.
  • retryUntil() рећи: „покушавај поново колико год желиш до овог тренутка, после тога је неуспех.“ Ако се поклопи са tries, команда retryUntil.
  • $maxExceptions да се прекине када је проблем последица поновљених необрађених изузетака.
  • $timeout o --timeout да би се назначило колико секунди посао може да се извршава пре него што радник убије подређени процес.
  • $failOnTimeout да означи задатак као неуспешан у случају истека времена.
  • $backoff метод backoff() да дефинише колико дуго треба чекати између поновних покушаја, чак и са експоненцијалним вредностима.

Ако посао избаци неухваћен изузетак, Ларавел ће... испушта назад у реп док се не исцрпе конфигурисани покушаји. Ово можете ручно контролисати помоћу release($segundos) o fail($exception) када желите намерно да означите посао као неуспешан.

Неуспешни послови, табела failed_jobs и одсецање

Када Јов исцрпи своје покушаје, почиње да се сматра неуспешан рад и Ларавел га убацује у табелу failed_jobs (или у DynamoDB-у ако га тако конфигуришете). Та табела чува UUID, везу, ред чекања, корисни терет посла и изузетак који је избачен.

Корисне команде:

  • php artisan queue:failed да наведе оне који су пропали.
  • php artisan queue:retry <id|all> да их поново испробам.
  • php artisan queue:forget <id> да обришете један.
  • php artisan queue:flush да обришете све (са опцијом за сате у новијим верзијама).
  • php artisan queue:prune-failed --hours=48 да аутоматски обрише старе записе.

У пословима можете дефинисати метод failed(Throwable $exception) За додатно чишћење: обавестите корисника, вратите делимичне радње, пишите специјализоване логове итд. Имајте на уму да се креира нова инстанца посла за позивање failed()Стога се не ослањајте на промене својстава направљене у handle().

Груписање послова: групе послова и њихово комбиновање помоћу стрингова

Када треба да покренете стотине или хиљаде повезаних задатака (на пример, увоз огромног CSV-а у деловима, обрада датотека у групама, чишћење података итд.), препоручљиво је користити Laravel-ову функционалност за групно обраду .

Основни ток:

  • креирајте табелу job_batches са php artisan queue:batches-table && php artisan migrate.
  • Означите послове који ће бити део серија особином Batchable.
  • Употреба Bus::batch() да пошаље скуп послова, са повратним позивима then, catch y finally.
  • Приступите групи из сваког посла помоћу $this->batch() и проверите да ли је отказано.
  • Могућност додавања више послова у текућу групу са $this->batch()->add().

Групе се лепо интегришу са ланцима : можете имати ланце унутар групе или групе као елементе већег ланца. Ово је посебно корисно када желите да више ланаца ради „паралелно“ и покрене нешто када се сви заврше.

Извршење радника, приоритети и распоређивање

Сва магија редова се дешава зато што имате један или више радника покретање команде queue:work (o queue:listen(иако је ово друго мање ефикасно). Ови процеси су дуготрајни демони који слушају своје одговарајуће редове чекања.

Кључне опције queue:work:

  • цонекион: php artisan queue:work redis, queue:work database, Итд
  • Цолас: --queue=high,default,low дати приоритет.
  • -једанаест: обрађује један задатак и излази.
  • –max-jobs: обрађује X задатака и завршава (да би периодично поново покренуо раднике и ослободио меморију).
  • –максимално време: обрађује се N секунди, а затим се затвара.
  • –сан: секунде чекања када нема доступних послова.
  • –заустави-када-је-празно: празни ред и чисто се затвара (идеално у Докер окружењима или једнократним задацима).
  • –временски аут: секунде временског ограничења по задатку, као што смо већ поменули.
  • -сила: да обрађује послове чак и ако је апликација у режиму одржавања.

Пошто се ови процеси дуго извршавају, у продукцији се скоро увек користи монитор процеса попут Supervisor-а (на Linux-у) за покретање X радника, њихово поновно покретање ако дође до пада и управљање логовима. Типичан конфигурациони блок Supervisor-а за Laravel дефинише:

  • команда са php artisan queue:work ... бетон.
  • бројпроцеса да назначи колико радника треба покренути паралелно.
  • Путање дневника, корисник, аутоматско поновно покретање итд.

Паузирање и настављање редова чекања у Ларавелу

Хајде да пређемо на оно што је често важно у одржавању: како паузирати раднике у реду чекања без њиховог наглог заустављања и без остављања послова недовршеним. Ларавел нуди неколико механизама, неке новије, неке класичне, за контролу овога.

Пауза: ред: сигнали паузе и прекида

У новијим верзијама, Laravel додаје специфичне команде за паузирање и наставак извршавања радника:

  • php artisan queue:pause: говори систему да престане да преузима нове задатке, али да дозволи да се они који су већ у току заврше.
  • php artisan queue:continue: наставља обраду нових задатака тамо где је стала.
  Које су дужности вебмастера?

Ове команде раде тако што шаљу сигнале радницима путем механизма кеширања који Laravel користи интерно. Зато је важно имати правилно конфигурисан драјвер кеша (memcached, redis, database, file, итд.) чак и ако је ваш стварни ред кеша нешто друго.

Важно: Паузирање реда или радника не отказује нити брише задатке који су већ у реду ; једноставно спречава уклањање додатних задатака из реда док пауза траје.

Анкетирање поремећаја и утицаја на перформансе

Сваки пут када радник заврши посао, Laravel проверава кеш меморију за сигнале за поновно покретање, паузу или наставак . Ово има занемарљиву цену, али постоји. Ако сте изузетно фокусирани на перформансе и знате да нећете морати да паузирате или поново покрећете раднике из команди, можете онемогућити ово анкетирање позивањем:

Queue::withoutInterruptionPolling();

Или чак подесите статичка својства Illuminate\Queue\Worker да бисте онемогућили одређене додире ($поново покреће, $pausableМеђутим, ако ово урадите, а затим покушате да користите queue:pause o queue:restartрадници Неће сазнатиТо је дизајнерска одлука коју треба пажљиво размотрити.

Ручно паузирајте помоћу Супервизора или Докера

Поред Ларавеловог сопственог командовања , у продукционим окружењима, процеси се често индиректно „паузирају“:

  • Заустављање програма у Супервизору (supervisorctl stop laravel-worker:*), што убија или зауставља раднике.
  • Коришћењем –заустави-када-је-празно у распоређивањима како би радници могли да заврше оно што је у реду чекања, а затим да се угасе.
  • У Докеру, пуштање контејнера да обрађује са --stop-when-empty а онда се искључује.

Разлика са queue:pause Потпуним заустављањем процеса, зауставићете обраду послова док се радници поново не покрену. унутрашња пауза Можете чувати процесе у меморији, чекајући команду continueОво је корисно за брза враћања на претходна имплементирања или кратке периоде одржавања.

Трансакције базе података и after_commit

Класична грешка: распоређивање послова унутар трансакција базе података . Ако нисте пажљиви, радник би могао да изврши посао пре него што се направи потврда (commit), а модел или подаци које очекујете можда још увек нису у бази података.

Да бисте избегли овај плес, имате две опције:

  • Активирати 'after_commit' => true у конфигурацији везе реда чекања. Стога се сваки посао послат у оквиру трансакције интерно одлаже док се не потврди.
  • Користите методе за сваки појединачни посао afterCommit() o beforeCommit() приликом отпреме, да би се понашање наметнуло само у одређеним пословима.

Ако се трансакција обрне, послови послати током ње се одбацују без уласка у ред чекања, што је управо оно што се обично жели ради одржавања конзистентности.

Праћење, чишћење реда и тестирање

Када једном озбиљно покренете редове, није довољно само избацити послове и заборавити на њих; требало би да пратите и тестирате како се све понаша.

Корисни алати и команде:

  • queue:clear да испразни одређени ред (SQS, Redis, база података).
  • queue:monitor да прати број послова у одређеним редовима чекања и покрене догађај QueueBusy ако пређу одређени праг.
  • Догађаји на послу као Queue::before, Queue::after, Queue::looping y Queue::failing да повеже прилагођену логику (логове, метрике, враћања на претходно стање итд.).
  • Фалсификати у тестирању коришћење Queue::fake() y Bus::fake() да би се проверило да ли су послови, низови или пакети послати без њиховог стварног извршавања.

У тестовима можете навести ствари попут „овај посао је стављен у ред X пута“ , „ланац са овим пословима је послат овим редоследом“ или „ниједан одређени посао није стављен у ред“, што пружа велику сигурност у сложеним токовима.

Са целим овим екосистемом - драјверима попут Redis-а или SQS-а, добро дизајнираним задацима, посредничким софтвером за фино подешавање, серијама, ланцима, конфигурацијом поновног покушаја, радницима којима управља супервизор и командама попут queue:pause y queue:continue— Ларавел вам омогућава да савладате позадинску обраду до милиметра, од типичног слања имејлова до дистрибуираних архитектура редова са пребацивањем у случају отказа, осигуравајући да ваша апликација настави брзо да реагује на HTTP слоју док се испод обавља тежак посао без блокирања корисника.

Ларавел Фрамеворк
Повезани чланак:
Моћни Ларавел оквир