Last active
April 8, 2024 14:39
-
-
Save Geovanek/388bf4c5af2ccffc4bc72548c94222c4 to your computer and use it in GitHub Desktop.
Job, Performance e atualização em massa no BD.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Estou com um problema de como otimizar uma atualização em massa no BD. Esses dias fiz um script e um job para isso e detonei com o servidor. | |
Em grande partes, pois estava passando informação em DTO, o que estourou a memória do servidor, consequentemente derrubava o Redis e dava erro 500. Depois o disco encheu tbm. Eram uns 300k de jobs gerados | |
Em resumo, sorte que estava com um Load Balancer, coloquei outro servidor e derrubei aquele. | |
Vou tentar explicar o que quero fazer. | |
Estou implementando uma funcionalidade nova na plataforma para análise dos dados de potência das atividades de ciclismo dos atletas, criar o Perfil de Potência, para tal, gostaria de fazer uma "re-análise" das atividades cadastradas desde 2021. | |
Minha primeira ideia é pegar todas as atividades de todos os atletas que se encaixem no critério abaixo: | |
```php | |
$activities = PerformedActivity::where('device_watts', true) | |
->where('performed_at', '>=', Carbon::parse('2021-01-01 00:00:00')) | |
->select( | |
'id', | |
'name', | |
'athlete_id', | |
'event_type_id', | |
'has_heartrate', | |
'performed_at', | |
) | |
->with([ | |
'eventType:id,activity_config_id', | |
'athlete:id' => [ | |
'users:id,sex,birthday', | |
], | |
]) | |
->lazy(); | |
``` | |
Aí eu faria uma inserção em massa no BD, minha dúvida é se seria bom fazer isso bia job, tipo usar chunk e disparar jobs para a inserção considerando que devem ter umas 8k de atividades atualmente no BD. | |
E aí vem minha primeira duvida, como proceder a partir daí? | |
Pensei em salvar tudo em uma tabela de `tasks`, com os dados básicos e depois ir disparando pouco a pouco via `schedule` os jobs para executarem a análise das atividades. | |
Basicamente, tentando resumir, a análise da atividade pega os **streams** de FC, Tempo, Potência e Cadência para buscar as melhores médias em diversos intervalos de tempo (1s, 2s, 3s, ... 1h, 2h,...) são 168 `timeSearch` se não me engano. | |
Isso seria um primeiro **Job** para a primeira análise, pegar as melhores médias. | |
Consegui otimizar esse Job e esta demorando em torno de 1,6s para fazer toda análise. | |
Nele eu gero um `Bus::batch` | |
```php | |
$BestPowerEffortsJobs[] = new BestPowerEffortJob( | |
interval: $bestEfforts['interval'], | |
athleteId: $this->athleteId, | |
performedActivityId: $activity->id, | |
activityConfigId: $activity->eventType->activity_config_id, | |
eventTypeId: $activity->eventType->id, | |
age: $athleteAge, | |
sex: $athleteSex, | |
absoluteValue: $bestEfforts['absoluteValue'], | |
relativeValue: $bestEfforts['relativeValue'], | |
startIndex: $bestEfforts['startIndex'], | |
endIndex: $bestEfforts['endIndex'], | |
averageHeartrate: $bestEfforts['averageHeartrate'], | |
peakHeartrate: $bestEfforts['peakHeartrate'], | |
averageCadence: $bestEfforts['averageCadence'], | |
performedAt: $activity->performed_at, | |
); | |
Bus::batch($BestPowerEffortsJobs) | |
->name('BestPowerEffortsJob') | |
->onQueue('trainingAnalysis') | |
->allowFailures() | |
->finally(function () use ($athlete, $activity): void { | |
CheckNewRecordPowerJob::dispatch( | |
athleteId: $athlete->id, | |
coachId: $athlete->coach_id, | |
performedActivityId: $activity->id, | |
performedActivityName: $activity->name, | |
performedAt: $activity->performed_at | |
)->delay(60); | |
}) | |
->dispatch(); | |
``` | |
E aí são disparados em torno de 150 a 180 jobs, rápidos, 0,6s cada normalmente. | |
E no final mais um JOB para chegar se é a melhor marca do atleta de todos os tempos ou da temporada. | |
Se for algum melhor valor, dispara um e-mail. | |
O problema inicial que eu tive do DTO eu consegui resolver, pois antes mandava mto informação para dentro do Batch (info repetida), puxei isso direto pro JOB onde gero o Batch e ficou bem mais rápido e menos memória (isso em uma única atividade). | |
A dúvida é como proceder para gerar uma análise em massa? | |
Vendo esse post do Matheus Guimarães, pensei que utilizar uma tabela de `tasks` seria uma boa opção | |
https://mateusguimaraes.com/posts/scaling-laravel |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment