|
55665
|
1932
|
2
|
2026-05-19T06:37:37.149200+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779172657149_m1.jpg...
|
Firefox
|
NULL
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
ClaudeFileEditViewWindowHelpDaily - Platform • in ClaudeFileEditViewWindowHelpDaily - Platform • in 8 m100% <78• Tue 19 May 9:37:36sshAPP (-zsh)DOCKER• ₴1DEV (-zsh)₴2*3screenpipe"WARN [0000]/volume2/docker/location-logger/docker-compose.yml:"version'is obsolete[+] Building 3.1s (25/25) FINISHED= [api internal] load build definitionfrom Dockerfile= => transferring dockerfile: 567B= [api] resolve imageconfig for [URL_WITH_CREDENTIALS] [api internal] load build definitionfrom Dockerfile=> WARN: JSONArgsRecommended: JSONargumentsrecommended for CMD to prevent unintended behavior related to 0S signals (line 21)=>[mcp internal]load metadata for= [api internal] loaddocker.io/library/python:3.11-slimdockerignore=>= transferringcontext:2B=> [apі 1/7]FROM docker.io/library/python:3.11-slim=> [api internal] loadbuildcontext= => transferring context: 60.33kB=> CACHED [api 2/7] WORKDIR/app=> CACHED [api 3/7] COPY requirements.txt /app/=> CACHED [api 4/7] RUN pip install--no-cache-dir -r requirements.txt=>[apі 5/7]COPY app /app/app=>[api 6/7] COPY alembic /app/alembic= [api 7/7] COPY alembic.ini /app/alembic.ini=> [api] exporting to image= =› exporting layers=> => writingimage sha256:0b6f06ab29cc13dc1256d9e8240bc4bbd7ab34630040c12aae54547fb10233ec= =› naming to docker.io/library/location-logger-api= [mcp internal] load build definition from Dockerfile= transferring dockerfile: 715B[mcp internal] loaddockerignore= transferring context: 2B[mcp internal] load build context= transferring context: 115B[mcp 1/6] FROM docker.io/library/python:3.11-slim=> CACHED [mcp 2/6] WORKDIR /app=> CACHED [mcp 3/6] COPY requirements.txt /app/=> CACHED [mcp 4/6] RUN pip install --no-cache-dir -r requirements.txt=> CACHED [mcp 5/6] RUN SITE=$(python -c"import sysconfig; print(sysconfig.get_path('purelib'))")=> CACHED [mcp6/6]COPY server.py /app/=> [mcp] exporting to image=> =› exportinglayers= => writing image sha256:afd9cc01d29616aa089d8ca3b164aaec06a200e88872d3ad4e2a87432aa68bc0=>=> naming to docker.io/library/location-logger-mcp[+] Running 3/3• Container location-logger-postgresHealthy‹ Container location-logger-apiHealthy• Container location-logger-mcpStartedAdm1n@DXP4800PLUS-B5F8:/volume2/docker/location-logger$ |0 ₴4ssh&& sed-i's/enable_dns_rebinding_protection=True/enable_dns_rebindin*5docker:default0.050.0s0.950.0s0.050.0s0.0s0.0s0.0s0.050.150.0s0.0s0.0s0.050.2s0.250.2s0.250.250.050.0s0.0s0.0s0.050.0s0.050.050.0s0.050.050.0s0.0s0.0s0.050.0s0.0s0.0s0.0510.650.85...
|
NULL
|
3162549591265160746
|
NULL
|
click
|
ocr
|
NULL
|
ClaudeFileEditViewWindowHelpDaily - Platform • in ClaudeFileEditViewWindowHelpDaily - Platform • in 8 m100% <78• Tue 19 May 9:37:36sshAPP (-zsh)DOCKER• ₴1DEV (-zsh)₴2*3screenpipe"WARN [0000]/volume2/docker/location-logger/docker-compose.yml:"version'is obsolete[+] Building 3.1s (25/25) FINISHED= [api internal] load build definitionfrom Dockerfile= => transferring dockerfile: 567B= [api] resolve imageconfig for [URL_WITH_CREDENTIALS] [api internal] load build definitionfrom Dockerfile=> WARN: JSONArgsRecommended: JSONargumentsrecommended for CMD to prevent unintended behavior related to 0S signals (line 21)=>[mcp internal]load metadata for= [api internal] loaddocker.io/library/python:3.11-slimdockerignore=>= transferringcontext:2B=> [apі 1/7]FROM docker.io/library/python:3.11-slim=> [api internal] loadbuildcontext= => transferring context: 60.33kB=> CACHED [api 2/7] WORKDIR/app=> CACHED [api 3/7] COPY requirements.txt /app/=> CACHED [api 4/7] RUN pip install--no-cache-dir -r requirements.txt=>[apі 5/7]COPY app /app/app=>[api 6/7] COPY alembic /app/alembic= [api 7/7] COPY alembic.ini /app/alembic.ini=> [api] exporting to image= =› exporting layers=> => writingimage sha256:0b6f06ab29cc13dc1256d9e8240bc4bbd7ab34630040c12aae54547fb10233ec= =› naming to docker.io/library/location-logger-api= [mcp internal] load build definition from Dockerfile= transferring dockerfile: 715B[mcp internal] loaddockerignore= transferring context: 2B[mcp internal] load build context= transferring context: 115B[mcp 1/6] FROM docker.io/library/python:3.11-slim=> CACHED [mcp 2/6] WORKDIR /app=> CACHED [mcp 3/6] COPY requirements.txt /app/=> CACHED [mcp 4/6] RUN pip install --no-cache-dir -r requirements.txt=> CACHED [mcp 5/6] RUN SITE=$(python -c"import sysconfig; print(sysconfig.get_path('purelib'))")=> CACHED [mcp6/6]COPY server.py /app/=> [mcp] exporting to image=> =› exportinglayers= => writing image sha256:afd9cc01d29616aa089d8ca3b164aaec06a200e88872d3ad4e2a87432aa68bc0=>=> naming to docker.io/library/location-logger-mcp[+] Running 3/3• Container location-logger-postgresHealthy‹ Container location-logger-apiHealthy• Container location-logger-mcpStartedAdm1n@DXP4800PLUS-B5F8:/volume2/docker/location-logger$ |0 ₴4ssh&& sed-i's/enable_dns_rebinding_protection=True/enable_dns_rebindin*5docker:default0.050.0s0.950.0s0.050.0s0.0s0.0s0.0s0.050.150.0s0.0s0.0s0.050.2s0.250.2s0.250.250.050.0s0.0s0.0s0.050.0s0.050.050.0s0.050.050.0s0.0s0.0s0.050.0s0.0s0.0s0.0510.650.85...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
55667
|
1932
|
3
|
2026-05-19T06:37:38.506753+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779172658506_m1.jpg...
|
CleanShot X
|
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Drag to capture the scrolling part of the screen.
Drag to capture the scrolling part of the screen.
Please slow down...
?...
|
[{"role":"AXStaticText","text& [{"role":"AXStaticText","text":"Drag to capture the scrolling part of the screen.","depth":1,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Please slow down...","depth":1,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"?","depth":1,"on_screen":true,"role_description":"text"}]...
|
7867509229883505805
|
2083377975995365134
|
visual_change
|
hybrid
|
NULL
|
Drag to capture the scrolling part of the screen.
Drag to capture the scrolling part of the screen.
Please slow down...
?
ClaudeFilelWindowHelp<$ 0Daily - Platform - in 8 msshDOCKER• ₴1DEV (-zsh)$2APP (-zsh)*3screenpipe"WARN [0000]/volume2/docker/location-logger/docker-compose.yml:"version'is obsolete[+] Building3.1s (25/25)FINISHED= [api internal] load build definitionfrom Dockerfile==>transferring dockerfile: 567B[api] resolve imageconfig [URL_WITH_CREDENTIALS] loadbuilddefinitionfrom Dockerfile=> WARN: JSONArgsRecommended:JSONargumentsrecommended for CMD to prevent unintended behavior related to OS signals (line 21)=>[mcp internal]load metadata for[api internal] loaddocker.io/library/python:3.11-slim-dockerignore=>=> transferringcontext:2B[арі 1/7]FROMdocker.io/library/python:3.11-slim=> [api internal] loadbuildcontext=>transferringcontext:60.33KBCACHED[арі2/7] WORKDIR/app=>CACHED[api3/7] COPY requirements.txt /app/CACHED[aрі4/7] RUN pip install--no-cache-dirrequirements.txt[api 5/7]COPY app/app/app=>[api6/7].COPY alembic /app/alembic= [api 7/7] COPY alembic.ini /app/alembic.ini=>[api] exporting to imageDrag to capture the scrolling part of the screen.=>= exporting layers=> => writingimage sha256:0b6f06ab29cc13dc1256d9e8240bc4bbd7ab5405004001Z0ae54547TDI0255eC=> namingto docker.io/library/location-logger-api[mcp internal] load build definition from Dockerfiletransferring dockerfile: 715B[mcp internal] load-dockerignore= transferring context: 2B=>=>[mcp internal] load build context= transferring context: 115B[mcp 1/6]FROM docker.io/library/python:3.11-slimCACHED [mcp 2/6] WORKDIR /app=> CACHED[mcp 3/6]COPY requirements.txt /app/=> CACHED[mср 4/6]RUN pip install--no-cache-dir-r requirements.txtCACHED[тср5/6] RUN SITE=$(python -c"importsysconfig; print(sysconfig.get_path('purelib'))")CACHED Imcp6/6] COPYserver.py /app/[mcp] exportingto image=› exportinglayers=> =› writingimagesha256:afd9cc01d29616aa089d8ca3b164aaec06a200e88872d3ad4e2a87432aa68bc0=> => namingto docker.io/library/location-logger-mcp[+] Running 3/3‹ Container location-logger-postgresHealthy‹ Container location-logger-apiHealthy• Container location-logger-mcpStartedAdm1n@DXP4800PLUS-B5F8:/volume2/docker/location-logger$ U100% <70 &4ssh&& sed-i's/enable_dns_rebinding_protection=True/enable_dns_rebindinTue 19 May 9:37:38 •L881*5docker:default0.0s0.0s0.9s0.0s0.050.050.0s0.0s0.0s0.0s0.150.0s0.050.0s0.050.2s0.2s0.2s0.250.2s0.0s0.0s0.050.0s0.050.0s0.0s0.050.0s0.0s0.0s0.0s0.0s0.0s0.050.0s0.0s0.0s0.0510.650.85...
|
55665
|
NULL
|
NULL
|
NULL
|
|
55668
|
1933
|
3
|
2026-05-19T06:37:39.284343+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779172659284_m2.jpg...
|
CleanShot X
|
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Please slow down...
?
|
[{"role":"AXStaticText","text& [{"role":"AXStaticText","text":"Please slow down...","depth":1,"bounds":{"left":0.0,"top":0.990024,"width":0.059175532,"height":0.009976029},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"?","depth":1,"bounds":{"left":0.0,"top":0.990024,"width":0.005984043,"height":0.009976029},"on_screen":true,"role_description":"text"}]...
|
4318090145782937453
|
34111803465273606
|
click
|
hybrid
|
NULL
|
Please slow down...
?
ClaudecaltVIeWWindow02 Chato Please slow down...
?
ClaudecaltVIeWWindow02 Chato- Cowork+ New chatÔ Projects80 Artifactse CustomizeBu garian citizenshio apolication procesiDid I drive todavLast visit to LovechUpdating packages in Laravelscreenpipe sync scripttalling arter rece.Hubspot BadRequest headers debuggin,Monthlv expense tracking® How much have I spent for groc...April z0zo spenaing by categoryViewing retention nolicv in screennind* Happy Tuesday, LukasHow can I help you today?Opus 4.7 Adaptive• Write& Learn‹/> CodeÖ Lifestuff @ Claude's choiceRelaunch to updatelK Lukas. ProlE Checks 3Files changed 18app/Component/ES/Listeners/UpdateMultjpleTargetsListener.phpC@ -5,6 +5,7 @euse Jiminny Component ES AsyncUpdateElasticSearch;use Jiminny Contracts_ES Events UpdateMultipleEntities;use Psr\Log\LoggerInterface;C@ -26,7 +27,7 @@ public function handle(UpdateMultipleEntities Sevent): voidAsyncupdatet lasticsearch::bulkmarkcnt1t1esrorUpdatesevent->getUpdateTargetValue(),Sevent->aetentltles,Sevent->isPriority()Drag to capture the scrolling part of the screen.v app/Component/ES/Listeners/UpdateSingleTargetListener.php $dd -9,o +9,l dduseliminnv\Comnonent\FC\Actions|TrackFlastirCearch0nerations:use Jiminny \Component\E5 AsyncUpdatetlasticsearch;use Jiminny\Component\ES\Processor\EntityQueryBuilder;use Jiminny\Contracts\ES\Events\UpdateSingleEntity;use Psr.\Loq.LoqgerIntertace;C@ -30,6 +31,13 @@ public function handle(UpdateSingleEntity $event): void'entitvid' => sevent->aetEntitvid().if (Sevent->isSyncEvent()) {Sthis->handleSyncEvent (Sevent):• Dally - Platrorm • In om100% LzTue 19 May 9:37:38 •+432 -159 8002( 0 /18 viewed+2-10041 Vieweduse Jiminny Component_ES AsyncUpdateElasticSearch;+ use Jiminny|Component\ES\QueuePriorityEnum;use Jiminny Contracts ES Events UpdateMultipleEntities;AsvncUpdatetlasticsearch::bulkMarkent1tlesrorUpdatesevent->getUpdateTargetValue(),sevent=>aetcntltlesSevent→>isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum: :NORMAL,+9 -1 88881O Vieweduse Jiminny\Component\ES\Actions\TrackElasticSearchOperations;use Jiminny Component\E5 AsyncUpdatetlasticsearch;use Jiminny\Component\ES\Processor\EntityQueryBuilder;+ use Jiminny \Component\ES QueuePr1or1tyenum;use Jiminny\Contracts\ES\Events\UpdateSingleEntity;use Psr\LoaLoqgerIntertace;'entityId' => $event->getEntityId(),* @important:* Synchronous event should eventually be deprecated.* Instant write onerations are blocking and should be used soarinalv.* It is much better in terms of performance to write 100 or 1000 documents at* and have one blocking reindex operation, instead of writing 10 documentsif (sevent->icSvncFvent()) &Sthis->handleSyncEvent(Sevent);...
|
55666
|
NULL
|
NULL
|
NULL
|
|
55669
|
1933
|
4
|
2026-05-19T06:37:47.109177+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779172667109_m2.jpg...
|
CleanShot X
|
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Start Capture
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Start Capture","depth":1,"bounds":{"left":0.72855717,"top":0.11412609,"width":0.04288564,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false}]...
|
-5531532117486019995
|
-7689366506145081254
|
click
|
hybrid
|
NULL
|
Start Capture
claudecaltVIeWWindow02 Chato- Cowork Start Capture
claudecaltVIeWWindow02 Chato- Cowork+ New chatÔ Projects80 Artifactse CustomizeBu garian citizenshio apolication procesiDid I drive todavLast visit to LovechUpdating packages in Laravelscreenpipe sync scripttalling arter rece.Hubspot BadRequest headers debuggin,Monthlv expense tracking® How much have I spent for groc...April z0zo spenaing by categoryViewing retention nolicv in screennind* Happy Tuesday, LukasHow can l help you today?Opus 4.7 Adaptive• Write& Learn</> CodeÖ Lifestuff @ Claude's choiceRelaunch to updatelK Lukas. ProlEy Checks 3Files changed 18v app/Component/ES/Listeners/UpdateMultipleTargetsListener.php D +@ -5,6 +5,7 @namespace J1minny_Component ES-L1steners:use Jiminny Component ES AsyncUpdateElasticSearch:use Jiminny\Contracts\E5\Events \UpdateMultipleentities;use Psr|Log\LoggerInterface;@ -26,7 +27,7 @ public function handle(UpdateMultipleEntities $event): voidAsyncupdatet lasticsearch::bulkMarkcnt1tlesrorUpdatesevent->getUpdateTargetValue(),Sevent->getcntltles.Sevent->isPriority()v app/Component/ES/Listeners/UpdateSingleTargetListener.php *dd -9,0 +9,l dcuse Jiminny\Component\ES\Actions\TrackElasticSearch0perations;use Jiminny Component\t5 AsyncUpdatetlasticsearch;use Jiminny|Component\ES\Processor\EntityQueryBuilder;use Jiminny\Contracts\ES\Events\UpdateSingleEntity:use Psr\Loa LoqgerIntertaceee -30,6 +31,13 @@ public function handle(UpdateSingleEntity $event): void'entityId' => $event->getEntityId(),if (Sevent->icSvncFvent()) {Sthis->handleSyncEvent (Sevent);• Dally - Platrorm • In omi Start Capture( 0 118 viewed100% C8Tue 19 May 9:37:46 •+432 -159 BBBB:+2-1884Viewednamespace J1m1nny Component\E5\L1steners;use Jiminny _Component_ES AsyncUpdateElasticSearch:+ use Jiminny|Component\ES\QueuePriorityEnum;use Jiminny Contracts ES Events UpdateMultipleEntities:use Psr\Log\LoggerInterface;Asyncupdatet lasticsearch::bulkMarkcnt1tlesrorUpdatesevent->getUpdateTargetValue(),sevent->aetcntltlessevent->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum: :NORMAL,+9 -1 00883• Vieweduse Jiminny|Component\ES\Actions\TrackElasticSearchOperations;use Jiminny Component\t5 AsyncUpdatetlasticsearch;use Jiminny|Component\ES\Processor\EntityQueryBuilder;12 + use Jiminny\Component\ES\QueuePriorityEnum:use Jiminny|Contracts\ES\Events\UpdateSingleEntity;use Psr\Loa LoqgerIntertace;'entityId' => $event->getEntityId(),* @important:* Synchronous event should eventually be deprecated.* Instant write operations are blocking and should be used sparingly.* It is much better in terms of performance to write 100 or 1000 documents at|once,* and have one blocking reindex operation, instead of writing 10 documentssynchronously.40 +if (sevent->i<SvncFvent()){ISthis->handleSyncEvent(Sevent);...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
55670
|
1932
|
4
|
2026-05-19T06:37:48.795496+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779172668795_m1.jpg...
|
CleanShot X
|
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Please slow down...
?
|
[{"role":"AXStaticText","text& [{"role":"AXStaticText","text":"Please slow down...","depth":1,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"?","depth":1,"on_screen":true,"role_description":"text"}]...
|
4318090145782937453
|
34111803465273606
|
visual_change
|
hybrid
|
NULL
|
Please slow down...
?
ClaudeFilelWindowHelp‹$0Dail Please slow down...
?
ClaudeFilelWindowHelp‹$0Daily - Platform - in 8 mlsshDOCKER• ₴1DEV (-zsh)$2APP (-zsh)*3screenpipe"WARN [0000]/volume2/docker/location-logger/docker-compose.yml:'version'is obsolete[+] Building3.1s (25/25)FINISHED= [api internal] load build definitionfrom Dockerfile==>transferring dockerfile: 567B=> [api] resolve imageconfig [URL_WITH_CREDENTIALS] [api internal] loadbuilddefinitionfrom Dockerfile=> WARN: JSONArgsRecommended:JSONargumentsrecommended for CMD to prevent unintended behavior related to OS signals (line 21)=>[mcp internal]load metadata for[api internal] loaddocker.io/library/python:3.11-slim-dockerignore=>= transferringcontext:2B=> [apі 1/7]FROMdocker.io/library/python:3.11-slim=> [api internal] loadbuildcontext=>= transferringcontext:60.33KB=> CACHED[арі2/7] WORKDIR/app=> CACHED[apі3/7] COPY requirements.txt /app/CACHED[aрі4/7] RUN pip install--no-cache-dir -r requirements.txt[api 5/7]COPY app/app/app=>[api 6/7] COPY alembic /app/alembic= [api 7/7] COPY alembic.ini /app/alembic.ini=>[api] exporting to image= exporting layers=> => writingimage sha256:0b6f06ab29cc13dc1256d9e8240bc4bbd7ab34630040c12aae54547fb10233ec= naming to docker.io/library/location-logger-api[mcp internal] load build definition from Dockerfile=>= transferring dockerfile: 715B[mcp internal] loaddockerignore= transferring context: 2B[mcp internal] load build context= transferring context: 115B[mcр 1/6]|FROM docker.io/library/python:3.11-slimCACHED [mcp 2/6] WORKDIR /app=> CACHED[mcp 3/6]COPY requirements.txt /app/=> CACHED[mср 4/6]RUN pip install --no-cache-dir -r requirements.txtCACHED[тср5/6] RUN SITE=$(python -c"import sysconfig; print(sysconfig.get_path('purelib'))")=>CACHED Imcp6/6] COPYserver.py /app/[mcp] exporting to image=› exportinglayers= =› writing image sha256:afd9cc01d29616aa089d8ca3b164aaec06a200e88872d3ad4e2a87432aa68bc0=> => naming to docker.io/library/location-logger-mcp|[+] Running 3/3‹ Container location-logger-postgresHealthy‹ Container location-logger-apiHealthy• Container location-logger-mcpStartedAdm1n@DXP4800PLUS-B5F8:/volume2/docker/location-logger$ U100% <7884&& sed-i 's/enable_dns_rebinding_protection=True/enable_dns_rebindin8 • Tue 19 May 9:37:48L881ssh*5docker:default0.0s0.0s0.9s0.0s0.050.050.0s0.0s0.0s0.0s0.150.0s0.050.0s0.050.2s0.2s0.2s0.250.2s0.0s0.0s0.0s0.0s0.0s0.0s0.0s0.050.0s0.0s0.0s0.0s0.050.0s0.0s0.0s0.050.050.0510.6s0.85...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
55671
|
1933
|
5
|
2026-05-19T06:37:52.026513+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779172672026_m2.jpg...
|
CleanShot X
|
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Please slow down...
?
|
[{"role":"AXStaticText","text& [{"role":"AXStaticText","text":"Please slow down...","depth":1,"bounds":{"left":0.72041225,"top":0.5482841,"width":0.059175532,"height":0.018355945},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"?","depth":1,"bounds":{"left":0.74700797,"top":0.5482841,"width":0.005984043,"height":0.018355945},"on_screen":true,"role_description":"text"}]...
|
4318090145782937453
|
34111803465273606
|
visual_change
|
hybrid
|
NULL
|
Please slow down...
?
ClaudecaltVIeWWindow02 Chato Please slow down...
?
ClaudecaltVIeWWindow02 Chato- Cowork+ New chatÔ Projects80 Artifactse CustomizeBu garian citizenshio apolication procesiDid I drive todavLast visit to LovechUpdating packages in Laravelscreenpipe sync scripttalling arter rece.Hubspot BadRequest headers debuggin,Monthlv expense tracking® How much have I spent for groc...April z0zo spenaing by categoryViewing retention nolicv in screennind* Happy Tuesday, LukasHow can l help you today?• WriteOpus 4.7 Adaptive -& Learn</> CodeQ Life stuff• Claude's choiceRelaunch to updatelK Lukas. Prolxing queue #12082wants to merge 36 commits into master trom Jy-26808-Low-pr1or1ty-1ndexing-queuev app/Component/ES/Listeners/UpdateSingleTargetListener.php Luse Fsr Loo Loogerintertace;Ce -30,6 +31,13 @ public function handle(UpdateSingleEntity sevent): void'entityld' => $event->getEntityId(),x Cancelif (Sevent->isSyncEvent@)<|Sthis->hand lesyncevent(sevent);C -39,7 +47,7 @@ public function handle(UpdateSingleEntity sevent): voidAsvncUodateElasticSearch::markEntitvForUodate(Sevent->qetUpdatelargetvalue),Sevent->getEntityId(),sevent->isPriority()50 +$0• Dally - Platrorm • In om100% S7• lue Ty May 9.3/:01• 0 / 18 viewec• Awaiting approval(1 W0+9 -1 0000v DoneViewedJiminny Contracts\ES Events UodateSinaleEntitv:use Psr lod Loggerintertace;'entityld' => Sevent->getEntityld(),* gimportant:* Synchronous event should eventually be deprecated.* Instant write operations are blocking and should be used sparingly.* It is much better in terms of performance to write 100 or 1000 documents at|once,* and have one blocking reindex operation, instead of writing 10 documentssynchronously.if (Sevent->isSvncEvent@)<|Sthis->handleSyncEvent(Sevent);AsvncUodateElasticSearch::markEntitvForUodate($event->qetUpdateTargetValue(),Sevent->aetEntitvIdo.sevent->isPriority() ? QueuePriorityEnum: :HIGH : QueuePriorityEnum: :NORMAL,v app/Component/ES/Processor/Actions/UpsertDocumentsAction-php d *ee -14,6 +14,7 @use Jiminnv\Conoonent\ES\Processor\DTOs\SimoleCollection:|use Jiminny|Component\ES|Processor\ResponseEvaluator;use Jiminnv\Conoonent\ES\Processor\Traits\UodateTaraetTrait•|17use Jiminny\Exceptions\InvalidDataException;use sencry Laravel racade as sentry:-132,7 +133,7 @@ public function pushSingleDocument(Document $document): intAsynCUpdateElasticSearch::markEntityForUpdate(entityType: $this->updateTarget,entityld: (ant) sdocument=>getidt),135 -use Jiminnv\Comoonent\ES\Processor\DTOs\SimoleCollection:|use Jiminny component cs Processor kesponsetvaluator;use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait;+use Jiminny|Component\ES\QueuePriorityEnum;use Jiminny|Exceptions\InvalidDataException;use Sentry\Laravel\Facade as Sentry:AsyncUpdatet lasticsearch::marktnt1tyrorUpdate(entitvTvne: Sthis->undateTaraet.entatyld: (int) Sdocument->getld()136 +prioritv: OueuePrioritvEnum::HIGH.+2 -1087• Viewed...
|
55669
|
NULL
|
NULL
|
NULL
|
|
55672
|
1933
|
6
|
2026-05-19T06:38:25.220470+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779172705220_m2.jpg...
|
CleanShot X
|
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Please slow down...
?
|
[{"role":"AXStaticText","text& [{"role":"AXStaticText","text":"Please slow down...","depth":1,"bounds":{"left":0.72041225,"top":0.5482841,"width":0.059175532,"height":0.018355945},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"?","depth":1,"bounds":{"left":0.74700797,"top":0.5482841,"width":0.005984043,"height":0.018355945},"on_screen":true,"role_description":"text"}]...
|
4318090145782937453
|
34111803465273606
|
visual_change
|
hybrid
|
NULL
|
Please slow down...
?
claudecaltVIeWWindow02 Chato Please slow down...
?
claudecaltVIeWWindow02 Chato- Cowork+ New chatÔ Projects80 Artifactse CustomizeBu garian citizenshio apolication procesiDid I drive todavLast visit to Lovech* Happy Tuesday, LukasHow can I help you today?Opus 4.7 Adaptive v• Write& Learn‹/> Code Lifestuff@ Claude's choiceUpdating packages in Laravelscreenpipe sync scripttalling arter rece.Hubspot BadRequest headers debuggin,Monthlv expense tracking® How much have I spent for groc...April z0zo spenaing by categoryViewing retention nolicv in screennindRelaunch to updatelK Lukas. ProlDally - Platorm• In /mxing queue #12082wants to merge 36 commits into master from JY-20808-low-priority-indexing-queue• 0 / 18 viewec• Awaiting approvalapp/Component/ES/QueuePriorityEnum.php Cx CancelDonecase HIGH = 'high';case NorMAL = "normal':case LOW = 'low';public static function tryFromString(string $value): selfif (! self::isValid(Svalue)) (throw new Inval1dArqumentException(sprintf('Invalid queue priority "&s" selected', svalue)return self::tryFrom(Svalue);public static function isValid(strina Svalue: boolreturn self::tryFrom(Svalue !== null:public function isLow(): boolreturn $this === self::LOW;public function isHiaho: boolreturn Sthis === self::HIGH:100% C42 &• Tue 19 May 9:38:25ubmit review - ộ+40 00000 Viewed•••app/Component/ES/UpdateProcessManager.php (da -81.6 +81.7 Oa oublic tunction doUndateEntitleschunk: boollif (SselectionList->isEmpty()) {|return talse:84 +* A stale chunk will alwavs be smaller than a regular chunk.* That doesn't mean there aren't any other scheduled entities for processing@e -158,14 +159,16 @@ private function executeUpdate(SimpleCollection $documentsToUpdate, SelectionLisnrivate function reccheduleThrot+1tities(Celectionl ict <celectionl ict). void+12 -9 mmaa[ Viewedif (SselectionList->isEmpty()) {return talse:* A stale chunk will alwavs be smaller than a regular chunk.* That doesn't mean there aren't any other scheduled entities for processingprivate function rescheduleThrottledEntities(SelectionList $selectionList): void...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
55673
|
1932
|
5
|
2026-05-19T06:38:36.796859+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779172716796_m1.jpg...
|
CleanShot X
|
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Please slow down...
?
|
[{"role":"AXStaticText","text& [{"role":"AXStaticText","text":"Please slow down...","depth":1,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"?","depth":1,"on_screen":true,"role_description":"text"}]...
|
4318090145782937453
|
34111803465273606
|
idle
|
hybrid
|
NULL
|
Please slow down...
?
ClaudeFilelWindowHelpDaily - Please slow down...
?
ClaudeFilelWindowHelpDaily - Platform • in 7 ml100% <7sshAPP (-zsh)DOCKERDEV (-zsh)$2*3screenpipe"WARN [0000]/volume2/docker/location-logger/docker-compose.yml:'version'is obsolete[+] Building3.1s (25/25)FINISHED= [api internal] load build definitionfrom Dockerfile==>transferring dockerfile: 567B=> [api] resolve imageconfig [URL_WITH_CREDENTIALS] [api internal] loadbuilddefinitionfrom Dockerfile=> WARN: JSONArgsRecommended:JSONargumentsrecommended for CMD to prevent unintended behavior related to OS signals (line 21)=>[mcp internal]load metadata for[api internal] loaddocker.io/library/python:3.11-slim-dockerignore=>= transferringcontext:2B=> [apі 1/7]FROMdocker.io/library/python:3.11-slim=> [api internal] loadbuildcontext=>= transferringcontext:60.33KB=> CACHED[арі2/7] WORKDIR/app=> CACHED[apі3/7] COPY requirements.txt /app/CACHED[aрі4/7] RUN pip install--no-cache-dir -r requirements.txt[api 5/7]COPY app/app/app=>[api 6/7] COPY alembic /app/alembic= [api 7/7] COPY alembic.ini /app/alembic.ini=>[api] exporting to image= exporting layers=> => writingimage sha256:0b6f06ab29cc13dc1256d9e8240bc4bbd7ab34630040c12aae54547fb10233ec= naming to docker.io/library/location-logger-api[mcp internal] load build definition from Dockerfile=>= transferring dockerfile: 715B[mcp internal] loaddockerignore= transferring context: 2B[mcp internal] load build context= transferring context: 115B[mcр 1/6]|FROM docker.io/library/python:3.11-slimCACHED [mcp 2/6] WORKDIR /app=> CACHED[mcp 3/6]COPY requirements.txt /app/=> CACHED[mср 4/6]RUN pip install --no-cache-dir -r requirements.txtCACHED[тср5/6] RUN SITE=$(python -c"import sysconfig; print(sysconfig.get_path('purelib'))")=>CACHED Imcp6/6] COPYserver.py /app/[mcp] exporting to image=› exportinglayers= =› writing image sha256:afd9cc01d29616aa089d8ca3b164aaec06a200e88872d3ad4e2a87432aa68bc0=> => naming to docker.io/library/location-logger-mcp|[+] Running 3/3‹ Container location-logger-postgresHealthy‹ Container location-logger-apiHealthy• Container location-logger-mcpStartedAdm1n@DXP4800PLUS-B5F8:/volume2/docker/location-logger$ U884&& sed-i 's/enable_dns_rebinding_protection=True/enable_dns_rebindin8• Tue 19 May 9:38:36L881ssh*5docker:default0.0s0.0s0.9s0.0s0.050.050.0s0.0s0.0s0.0s0.150.0s0.050.0s0.050.2s0.2s0.2s0.250.2s0.0s0.0s0.0s0.0s0.0s0.0s0.0s0.050.0s0.0s0.0s0.0s0.050.0s0.0s0.0s0.050.050.0510.6s0.85...
|
55670
|
NULL
|
NULL
|
NULL
|
|
55674
|
1932
|
6
|
2026-05-19T06:38:39.585593+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779172719585_m1.jpg...
|
CleanShot X
|
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Cancel
Done
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Cancel","depth":1,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false},{"role":"AXButton","text":"Done","depth":1,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false}]...
|
9213889471338599672
|
5284964174291632892
|
click
|
hybrid
|
NULL
|
Cancel
Done
ClaudeFilelWindowHelpDaily - Platform Cancel
Done
ClaudeFilelWindowHelpDaily - Platform • in 7 ml100% <7sshAPP (-zsh)DOCKERDEV (-zsh)$2*3screenpipe"WARN [0000]/volume2/docker/location-logger/docker-compose.yml:'version'is obsolete[+] Building3.1s (25/25)FINISHED= [api internal] load build definitionfrom Dockerfile==>transferring dockerfile: 567B=> [api] resolve imageconfig [URL_WITH_CREDENTIALS] [api internal] loadbuilddefinitionfrom Dockerfile=> WARN: JSONArgsRecommended:JSONargumentsrecommended for CMD to prevent unintended behavior related to OS signals (line 21)=>[mcp internal]load metadata for[api internal] loaddocker.io/library/python:3.11-slim-dockerignore=>= transferringcontext:2B=> [apі 1/7]FROMdocker.io/library/python:3.11-slim=> [api internal] loadbuildcontext=>= transferringcontext:60.33KB=> CACHED[арі2/7] WORKDIR/app=> CACHED[apі3/7] COPY requirements.txt /app/CACHED[aрі4/7] RUN pip install--no-cache-dir -r requirements.txt[api 5/7]COPY app/app/app=>[api 6/7] COPY alembic /app/alembic= [api 7/7] COPY alembic.ini /app/alembic.ini=>[api] exporting to image= exporting layers=> => writingimage sha256:0b6f06ab29cc13dc1256d9e8240bc4bbd7ab34630040c12aae54547fb10233ec= naming to docker.io/library/location-logger-api[mcp internal] load build definition from Dockerfile=>= transferring dockerfile: 715B[mcp internal] loaddockerignore= transferring context: 2B[mcp internal] load build context= transferring context: 115B[mcр 1/6]|FROM docker.io/library/python:3.11-slimCACHED [mcp 2/6] WORKDIR /app=> CACHED[mcp 3/6]COPY requirements.txt /app/=> CACHED[mср 4/6]RUN pip install --no-cache-dir -r requirements.txtCACHED[тср5/6] RUN SITE=$(python -c"import sysconfig; print(sysconfig.get_path('purelib'))")=>CACHED Imcp6/6] COPYserver.py /app/[mcp] exporting to image=› exportinglayers= =› writing image sha256:afd9cc01d29616aa089d8ca3b164aaec06a200e88872d3ad4e2a87432aa68bc0=> => naming to docker.io/library/location-logger-mcp|[+] Running 3/3‹ Container location-logger-postgresHealthy‹ Container location-logger-apiHealthy• Container location-logger-mcpStartedAdm1n@DXP4800PLUS-B5F8:/volume2/docker/location-logger$ U884&& sed-i 's/enable_dns_rebinding_protection=True/enable_dns_rebindin8• Tue 19 May 9:38:39L881ssh*5docker:default0.0s0.0s0.9s0.0s0.050.050.0s0.0s0.0s0.0s0.150.0s0.050.0s0.050.2s0.2s0.2s0.250.2s0.0s0.0s0.0s0.0s0.0s0.0s0.0s0.050.0s0.0s0.0s0.0s0.050.0s0.0s0.0s0.050.050.0510.6s0.85...
|
55670
|
NULL
|
NULL
|
NULL
|
|
55675
|
1933
|
7
|
2026-05-19T06:38:39.585601+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779172719585_m2.jpg...
|
CleanShot X
|
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Cancel
Done
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Cancel","depth":1,"bounds":{"left":0.71858376,"top":0.11412609,"width":0.029587766,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false},{"role":"AXButton","text":"Done","depth":1,"bounds":{"left":0.75482047,"top":0.11412609,"width":0.026595745,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false}]...
|
9213889471338599672
|
5284964174291632892
|
click
|
hybrid
|
NULL
|
Cancel
Done
ClaudecaltVIewWindow02 Chato- Cowork+ Cancel
Done
ClaudecaltVIewWindow02 Chato- Cowork+ New chatÔ Projects80 Artifactse CustomizeBu garian citizenshio apolication procesiDid I drive todavLast visit to LovechUpdating packages in Laravelscreenpipe sync scripttalling arter rece.Hubspot BadRequest headers debuggin,Monthlv expense tracking® How much have I spent for groc...April z0zo spenaing by categoryViewing retention nolicv in screennine* Happy Tuesday, LukasHow can I help you today?• WriteOpus 4.7 Adaptive -& Learn</> Code" Life stuff Claude's choiceRelaunch to updatelK Lukas. Prolxing queue #12082vants to merge 36 commits into master trom Jy-20808-low-pr1or1ty-1ndexing-queuev app/Console/Commands/Elasticsearch/AsyncUpdateEsEntities.php C $x Cancelsthis->gaugeStats(stat: sprintt( Jaminny•ss-Tor-update, supdatelarget),value: AsynCUpdateElasticSearch::getEntitiesListCount(SupdateTarget),sthis->gaugeStats(stat: sprintf('jiminny.%s-for-update-priority', SupdateTarget),value: AsyncUpdateElasticSearch: :getEntitiesListCount($updateTarget, true),Dally - Platorm• In /m100% Lz8• Tue 19 May 9:38:39• 0 / 18 viewec• Awaiting approval+9 -3 0002• Viewed•••Done97 +sthis->gaugeStats(stat: sprintf('jiminny.&s-for-update', SupdateTarget),value: AsyncUpdateElasticSearch::getEntitiesListCount(SupdateTarget,QueuePriorityEnum: :NORMAL),98100101sthis->gaugeStats(stat: sprintt(j1minny.s-tor-update-low, Supdatelarget),value: AsyncUpdateElasticSearch::getEntitiesListCount(SupdateTarget,QueuePriorityEnum::LOW),104~ app/Console/Comnands/Elasticsearch/ResetAsyncElasticSearchCommand-php +aa -9,6 +9,7 0duse Jiminny|Component\ES\Processor\EntityQueryBuilder;use Jiminny\Component\ES\Processor\Traits\ValidateUpdateTargetTrait:use Jiminny\Component\ES\Processor\UpdateTarget;147use Jiminnv\Comoonent\ES\Renositories\EsResetReoositorvInterface:use Jiminny \except1ons \1nval1dArqumentexcept1on;use Jiminny\Traits\GracefullyStoppable;@ -144,7 +145,10 @@ private function shouldResetElasticSearchInternals(): voidprivate function getRemainingScheduledEntities(bool SprintStatus = false): intSremainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount(Sthis->updateTarget);>uodateTaraet. true):SremainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount(Sthis-if (SprintStatus) (v tests/Unit/Component/ES/Processor/DTOs/SelectionListTest-php 0 *ee -5,84 +5,140 @+5 -1 88883• Viewed |use Jiminny|Component\ES\Processor\EntityQueryBuilder;use Jiminny Component\ts \Processor\lra1ts\Val1dateUpdatelargetiralt;use Jiminny\Component\ES\Processor\UpdateTarget;12 + use Jiminny|Component\ES\QueuePriorityEnum;use Jiminny|Component\ES\Repositories\EsResetRepositoryInterface;use Jiminny Exceptions\Inval1dArqumenttxcept1on;use Jiminny\Traits\GracefullyStoppable;145146147private function getRemainingScheduledEntities(bool $printStatus = false): intSremainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount(Sthis->updateTarget);148 +SremainingPriority = AsynCUpdateElasticSearch: :getEntitiesListCount(149150151Sthis->updateTarget,QueuePrioritvEnum::HIGH);if (sprintStatus) (+103 -47 вuna [ Viewed 0 ...namespace Tests\Unit\Component\ES\Processor\DTOs;...
|
55672
|
NULL
|
NULL
|
NULL
|
|
55677
|
1933
|
8
|
2026-05-19T06:38:42.243349+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779172722243_m2.jpg...
|
Firefox
|
JY-20808 low priority indexing queue by Vasil-Jimi JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app — Work...
|
1
|
github.com/jiminny/app/pull/12082/changes#diff-49a github.com/jiminny/app/pull/12082/changes#diff-49a79d99c97caf7fc27ecb1dbacab5a29d871822caa0db0c71e94957c28c87af...
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
Close tab
New Tab
Customize sidebar
Close Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
AI Chat settings
Close
WORK, Google Account: [EMAIL]
Main menu
New chat
Gemini
New Chat
Open menu for conversation actions....
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira","depth":4,"bounds":{"left":0.0,"top":0.0518755,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.06304868,"width":0.10106383,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app","depth":4,"bounds":{"left":0.0,"top":0.08459697,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app","depth":5,"bounds":{"left":0.013297873,"top":0.09577015,"width":0.18816489,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app","depth":4,"bounds":{"left":0.0,"top":0.11731844,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app","depth":5,"bounds":{"left":0.013297873,"top":0.12849163,"width":0.15674867,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.06732048,"top":0.1245012,"width":0.007978723,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New Tab","depth":4,"bounds":{"left":0.0028257978,"top":0.15163608,"width":0.07413564,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"bounds":{"left":0.0028257978,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Close Google Gemini (⌃X)","depth":6,"bounds":{"left":0.013796543,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Tabs from other devices","depth":6,"bounds":{"left":0.024933511,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"bounds":{"left":0.036070477,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"bounds":{"left":0.04720745,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"AI Chat settings","depth":7,"bounds":{"left":0.35854387,"top":0.055067837,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Close","depth":7,"bounds":{"left":0.37051198,"top":0.055067837,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"WORK, Google Account: lukas.kovalik@jiminny.com","depth":12,"bounds":{"left":0.3678524,"top":0.103751,"width":0.013297873,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Main menu","depth":12,"bounds":{"left":0.08494016,"top":0.103751,"width":0.013297873,"height":0.031923383},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New chat","depth":12,"bounds":{"left":0.09823803,"top":0.10454908,"width":0.028590426,"height":0.030327214},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Gemini","depth":15,"bounds":{"left":0.1008976,"top":0.10973663,"width":0.021941489,"height":0.020351157},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"New Chat","depth":12,"bounds":{"left":0.33992687,"top":0.103751,"width":0.013297873,"height":0.031923383},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Open menu for conversation actions.","depth":12,"bounds":{"left":0.35322472,"top":0.103751,"width":0.013297873,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
246148166065046644
|
5783261842424778917
|
click
|
accessibility
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
Close tab
New Tab
Customize sidebar
Close Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
AI Chat settings
Close
WORK, Google Account: [EMAIL]
Main menu
New chat
Gemini
New Chat
Open menu for conversation actions....
|
NULL
|
NULL
|
NULL
|
NULL
|
|
55676
|
1932
|
7
|
2026-05-19T06:38:42.243379+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779172722243_m1.jpg...
|
Firefox
|
JY-20808 low priority indexing queue by Vasil-Jimi JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app — Work...
|
1
|
github.com/jiminny/app/pull/12082/changes#diff-49a github.com/jiminny/app/pull/12082/changes#diff-49a79d99c97caf7fc27ecb1dbacab5a29d871822caa0db0c71e94957c28c87af...
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
Close tab
New Tab
Customize sidebar
Close Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
AI Chat settings
Close
WORK, Google Account: [EMAIL]
Main menu
New chat
Gemini
New Chat...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New Tab","depth":4,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Close Google Gemini (⌃X)","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Tabs from other devices","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"AI Chat settings","depth":7,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Close","depth":7,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"WORK, Google Account: lukas.kovalik@jiminny.com","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Main menu","depth":12,"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New chat","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Gemini","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"New Chat","depth":12,"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false}]...
|
-403519834127413198
|
5783538919354978981
|
click
|
accessibility
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
Close tab
New Tab
Customize sidebar
Close Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
AI Chat settings
Close
WORK, Google Account: [EMAIL]
Main menu
New chat
Gemini
New Chat...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
55678
|
1933
|
9
|
2026-05-19T06:38:49.650437+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779172729650_m2.jpg...
|
Firefox
|
JY-20808 low priority indexing queue by Vasil-Jimi JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app — Work...
|
1
|
github.com/jiminny/app/pull/12082/changes#diff-49a github.com/jiminny/app/pull/12082/changes#diff-49a79d99c97caf7fc27ecb1dbacab5a29d871822caa0db0c71e94957c28c87af...
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
Close tab
New Tab
Customize sidebar
Close Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
AI Chat settings
Close
WORK, Google Account: [EMAIL]
Main menu
New chat
Gemini
PRO
PRO
Conversation with Gemini
Conversation with Gemini
Hi Lukas
Where should we start?
Where should we start?
🖼️ Create image, button, tap to use tool
🖼️ Create image
🎸 Create music, button, tap to use tool
🎸 Create music
Write anything, button, tap to use tool
Write anything
Boost my day, button, tap to use tool
Boost my day
Help me learn, button, tap to use tool
Help me learn
Mak
Mak
Open upload file menu
Tools
Open mode picker
Pro
Send message
Summarize page
Summarize page
Skip to content
Skip to content
Open menu
Homepage (g then d)
jiminny
jiminny
app
app
Search or jump to…
Type
/
to search
Chat with Copilot
Open Copilot…
Create new...
All issues(g then i)
All pull requests
All repositories
You have unread notifications(g then n)
Open user navigation menu
Repository navigation
Repository navigation
Code
Code
Pull requests (31)
Pull requests
(
31
)
Agents
Agents
Actions
Actions
Wiki
Wiki
Security and quality (1)
Security and quality
(
1
)
Insights
Insights
Settings
Settings
Important update
Important update
On April 24 we'll start using GitHub Copilot interaction data for AI model training unless you opt out.
Review this update
Review this update
and manage your preferences in your
GitHub account settings
GitHub account settings
.
Dismiss banner
JY-20808 low priority indexing queue #12082 Edit title
JY-20808 low priority indexing queue
#
12082
Edit title
Preview
Preview
Awaiting approval
Awaiting approval
Code
Code
Open
Vasil-Jiminny
Vasil-Jiminny
wants to merge 36 commits into
master
master
from
JY-20808-low-priority-indexing-queue
JY-20808-low-priority-indexing-queue
Copy head branch name to clipboard
Lines changed: 432 additions & 159 deletions
Conversation (5)
Conversation
(
5
)
Commits (36)
Commits
(
36
)
Checks (3)
Checks
(
3
)
Files changed (18)
Files changed
(
18
)
Pull Request Toolbar
Pull Request Toolbar
Collapse file tree
Open
JY-20808 low priority indexing queue
JY-20808 low priority indexing queue
#
12082
All commits
All commits
Vasil-Jiminny
Vasil-Jiminny
wants to merge 36 commits into
master
master
from
JY-20808-low-priority-indexing-queue
JY-20808-low-priority-indexing-queue
Copy head branch name to clipboard
0 of 18 files viewed
Awaiting approval
Awaiting approval
Submit review
Submit
review
Open diff view settings
Open overview panel
Open comments panel
(
0
)
Filter files…
Filter options
File tree
File tree
app
Component/ES
Listeners
UpdateMultipleTargetsListener.php
UpdateMultipleTargetsListener.php
UpdateSingleTargetListener.php
UpdateSingleTargetListener.php
Processor
Actions
UpsertDocumentsAction.php
UpsertDocumentsAction.php
DTOs
SelectionList.php
SelectionList.php
Traits
SelectEntityListTrait.php
SelectEntityListTrait.php
TargetEntitiesSelector.php
TargetEntitiesSelector.php
AsyncUpdateElasticSearch.php
AsyncUpdateElasticSearch.php
QueuePriorityEnum.php
QueuePriorityEnum.php
UpdateProcessManager.php
UpdateProcessManager.php
Console/Commands/Elasticsearch
AsyncUpdateEsEntities.php
AsyncUpdateEsEntities.php
ResetAsyncElasticSearchCommand.php
ResetAsyncElasticSearchCommand.php
tests/Unit/Component/ES
Collapse file
app/Component/ES/Listeners/UpdateMultipleTargetsListener.php
app/Component/ES/Listeners/UpdateMultipleTargetsListener.php
app/Component/ES/Listeners/UpdateMultipleTargetsListener.php
Copy file name to clipboard
Expand all lines: app/Component/ES/Listeners/UpdateMultipleTargetsListener.php
Lines changed: 2 additions & 1 deletion
Not Viewed
Viewed
Comment on this file
More options
Original file line number
Original file line
Diff line number
Diff line change
@@ -5,6 +5,7 @@
5...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira","depth":4,"bounds":{"left":0.0,"top":0.0518755,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.06304868,"width":0.10106383,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app","depth":4,"bounds":{"left":0.0,"top":0.08459697,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app","depth":5,"bounds":{"left":0.013297873,"top":0.09577015,"width":0.18816489,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app","depth":4,"bounds":{"left":0.0,"top":0.11731844,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app","depth":5,"bounds":{"left":0.013297873,"top":0.12849163,"width":0.15674867,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.06732048,"top":0.1245012,"width":0.007978723,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New Tab","depth":4,"bounds":{"left":0.0028257978,"top":0.15163608,"width":0.07413564,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"bounds":{"left":0.0028257978,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Close Google Gemini (⌃X)","depth":6,"bounds":{"left":0.013796543,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Tabs from other devices","depth":6,"bounds":{"left":0.024933511,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"bounds":{"left":0.036070477,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"bounds":{"left":0.04720745,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"AI Chat settings","depth":7,"bounds":{"left":0.35854387,"top":0.055067837,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Close","depth":7,"bounds":{"left":0.37051198,"top":0.055067837,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"WORK, Google Account: lukas.kovalik@jiminny.com","depth":12,"bounds":{"left":0.3678524,"top":0.103751,"width":0.013297873,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Main menu","depth":12,"bounds":{"left":0.08494016,"top":0.103751,"width":0.013297873,"height":0.031923383},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New chat","depth":12,"bounds":{"left":0.09823803,"top":0.10454908,"width":0.028590426,"height":0.030327214},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Gemini","depth":15,"bounds":{"left":0.1008976,"top":0.10973663,"width":0.021941489,"height":0.020351157},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"PRO","depth":11,"bounds":{"left":0.35106382,"top":0.110135674,"width":0.014793883,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"PRO","depth":13,"bounds":{"left":0.3537234,"top":0.112529926,"width":0.009474734,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Conversation with Gemini","depth":15,"bounds":{"left":0.079288565,"top":0.14764565,"width":0.0003324468,"height":0.0007980846},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Conversation with Gemini","depth":16,"bounds":{"left":0.079288565,"top":0.15003991,"width":0.1200133,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Hi Lukas","depth":23,"bounds":{"left":0.11336436,"top":0.22027135,"width":0.027759308,"height":0.022346368},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Where should we start?","depth":22,"bounds":{"left":0.11336436,"top":0.24261771,"width":0.1165226,"height":0.028731046},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Where should we start?","depth":24,"bounds":{"left":0.11336436,"top":0.24102154,"width":0.11386303,"height":0.032322425},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"🖼️ Create image, button, tap to use tool","depth":22,"bounds":{"left":0.11336436,"top":0.2905028,"width":0.049534574,"height":0.03830806},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"🖼️ Create image","depth":24,"bounds":{"left":0.11868351,"top":0.30127692,"width":0.038896278,"height":0.016759777},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"🎸 Create music, button, tap to use tool","depth":22,"bounds":{"left":0.11336436,"top":0.33519554,"width":0.04886968,"height":0.03830806},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"🎸 Create music","depth":24,"bounds":{"left":0.11868351,"top":0.34596968,"width":0.038231384,"height":0.016759777},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Write anything, button, tap to use tool","depth":22,"bounds":{"left":0.11336436,"top":0.37988827,"width":0.045711435,"height":0.03830806},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Write anything","depth":24,"bounds":{"left":0.11868351,"top":0.39106146,"width":0.03507314,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Boost my day, button, tap to use tool","depth":22,"bounds":{"left":0.11336436,"top":0.424581,"width":0.04338431,"height":0.03830806},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Boost my day","depth":24,"bounds":{"left":0.11868351,"top":0.43575418,"width":0.03274601,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Help me learn, button, tap to use tool","depth":22,"bounds":{"left":0.11336436,"top":0.46927375,"width":0.044049203,"height":0.03830806},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Help me learn","depth":24,"bounds":{"left":0.11868351,"top":0.48044693,"width":0.033410903,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXTextArea","text":"Mak","depth":20,"bounds":{"left":0.11469415,"top":0.8567438,"width":0.23670213,"height":0.01915403},"on_screen":true,"value":"Mak","help_text":"","role_description":"text entry area","subrole":"AXUnknown","is_enabled":true,"is_focused":true,"is_selected":false},{"role":"AXStaticText","text":"Mak","depth":22,"bounds":{"left":0.11469415,"top":0.85833997,"width":0.009973404,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Open upload file menu","depth":20,"bounds":{"left":0.11070479,"top":0.89265764,"width":0.013297873,"height":0.031923383},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Tools","depth":18,"bounds":{"left":0.12666224,"top":0.89265764,"width":0.013297873,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Open mode picker","depth":20,"bounds":{"left":0.31399602,"top":0.8902634,"width":0.026097074,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pro","depth":23,"bounds":{"left":0.31931517,"top":0.8990423,"width":0.007480053,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Send message","depth":19,"bounds":{"left":0.3414229,"top":0.8894653,"width":0.013962766,"height":0.033519555},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Summarize page","depth":7,"bounds":{"left":0.08494016,"top":0.95730245,"width":0.053523935,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Summarize page","depth":9,"bounds":{"left":0.09059176,"top":0.96249,"width":0.042220745,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Skip to content","depth":6,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip to content","depth":7,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Open menu","depth":10,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Homepage (g then d)","depth":9,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"jiminny","depth":12,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"jiminny","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"app","depth":12,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"app","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Search or jump to…","depth":9,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Type","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"to search","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Chat with Copilot","depth":10,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXMenuButton","text":"Open Copilot…","depth":9,"on_screen":false,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXMenuButton","text":"Create new...","depth":9,"on_screen":false,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"All issues(g then i)","depth":9,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"All pull requests","depth":9,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"All repositories","depth":9,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"You have unread notifications(g then n)","depth":9,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Open user navigation menu","depth":9,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"Repository navigation","depth":9,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Repository navigation","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Code","depth":12,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Code","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Pull requests (31)","depth":12,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pull requests","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"31","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Agents","depth":12,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Agents","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Actions","depth":12,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Actions","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Wiki","depth":12,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Wiki","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Security and quality (1)","depth":12,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Security and quality","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Insights","depth":12,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Insights","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Settings","depth":12,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Settings","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Important update","depth":10,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Important update","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"On April 24 we'll start using GitHub Copilot interaction data for AI model training unless you opt out.","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review this update","depth":10,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review this update","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"and manage your preferences in your","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"GitHub account settings","depth":10,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"GitHub account settings","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":".","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Dismiss banner","depth":9,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"JY-20808 low priority indexing queue #12082 Edit title","depth":13,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"JY-20808 low priority indexing queue","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"12082","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Edit title","depth":14,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXMenuButton","text":"Preview","depth":13,"on_screen":false,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Preview","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Awaiting approval","depth":13,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Awaiting approval","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Code","depth":13,"on_screen":false,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Code","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Open","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Vasil-Jiminny","depth":15,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Vasil-Jiminny","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"wants to merge 36 commits into","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"master","depth":15,"on_screen":false,"role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"master","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"from","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"JY-20808-low-priority-indexing-queue","depth":16,"on_screen":false,"role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20808-low-priority-indexing-queue","depth":17,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy head branch name to clipboard","depth":16,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Lines changed: 432 additions & 159 deletions","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Conversation (5)","depth":16,"on_screen":false,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Conversation","depth":17,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"5","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Commits (36)","depth":16,"on_screen":false,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Commits","depth":17,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"36","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Checks (3)","depth":16,"on_screen":false,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Checks","depth":17,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Files changed (18)","depth":16,"on_screen":false,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"Files changed","depth":17,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"18","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Pull Request Toolbar","depth":14,"bounds":{"left":0.39993352,"top":0.075019956,"width":0.0003324468,"height":0.0007980846},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Pull Request Toolbar","depth":15,"bounds":{"left":0.39993352,"top":0.077813245,"width":0.030086435,"height":0.08060654},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Collapse file tree","depth":14,"bounds":{"left":0.39993352,"top":0.06424581,"width":0.00930851,"height":0.022346368},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXStaticText","text":"Open","depth":14,"bounds":{"left":0.4225399,"top":0.06863528,"width":0.011968086,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"JY-20808 low priority indexing queue","depth":14,"bounds":{"left":0.44115692,"top":0.057462092,"width":0.084773935,"height":0.016759777},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20808 low priority indexing queue","depth":16,"bounds":{"left":0.44115692,"top":0.05905826,"width":0.084773935,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#","depth":15,"bounds":{"left":0.52859044,"top":0.05905826,"width":0.0029920214,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"12082","depth":15,"bounds":{"left":0.5315825,"top":0.05905826,"width":0.013464096,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"All commits","depth":14,"bounds":{"left":0.43849733,"top":0.07102953,"width":0.03374335,"height":0.022346368},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"All commits","depth":16,"bounds":{"left":0.44148937,"top":0.07621708,"width":0.02244016,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Vasil-Jiminny","depth":15,"bounds":{"left":0.4765625,"top":0.075019956,"width":0.02642952,"height":0.014365523},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Vasil-Jiminny","depth":16,"bounds":{"left":0.4765625,"top":0.07621708,"width":0.02642952,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"wants to merge 36 commits into","depth":15,"bounds":{"left":0.5043218,"top":0.07621708,"width":0.06050532,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"master","depth":15,"bounds":{"left":0.5661569,"top":0.07342378,"width":0.018450798,"height":0.017557861},"on_screen":true,"role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"master","depth":16,"bounds":{"left":0.5681516,"top":0.07661612,"width":0.014461436,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"from","depth":16,"bounds":{"left":0.5859375,"top":0.07621708,"width":0.008643617,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"JY-20808-low-priority-indexing-queue","depth":16,"bounds":{"left":0.5959109,"top":0.07342378,"width":0.09042553,"height":0.017557861},"on_screen":true,"role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20808-low-priority-indexing-queue","depth":17,"bounds":{"left":0.5979056,"top":0.07661612,"width":0.08643617,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy head branch name to clipboard","depth":16,"bounds":{"left":0.68766624,"top":0.07102953,"width":0.00930851,"height":0.022346368},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"0 of 18 files viewed","depth":15,"bounds":{"left":0.81366354,"top":0.07661612,"width":0.01512633,"height":0.08060654},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Awaiting approval","depth":14,"bounds":{"left":0.85355717,"top":0.06424581,"width":0.04654255,"height":0.022346368},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Awaiting approval","depth":16,"bounds":{"left":0.86319816,"top":0.06943336,"width":0.033909574,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Submit review","depth":14,"bounds":{"left":0.9027593,"top":0.06424581,"width":0.03856383,"height":0.022346368},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Submit","depth":16,"bounds":{"left":0.90575135,"top":0.06943336,"width":0.014793883,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"review","depth":16,"bounds":{"left":0.9205452,"top":0.06943336,"width":0.012466756,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Open diff view settings","depth":14,"bounds":{"left":0.9439827,"top":0.06424581,"width":0.00930851,"height":0.022346368},"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Open overview panel","depth":14,"bounds":{"left":0.9616024,"top":0.06424581,"width":0.00930851,"height":0.022346368},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Open comments panel","depth":14,"bounds":{"left":0.9722407,"top":0.06424581,"width":0.017287234,"height":0.022346368},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"(","depth":16,"bounds":{"left":0.98055184,"top":0.06943336,"width":0.0026595744,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"0","depth":16,"bounds":{"left":0.98321146,"top":0.06943336,"width":0.0026595744,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")","depth":16,"bounds":{"left":0.985871,"top":0.06943336,"width":0.0014960107,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXTextField","text":"Filter files…","depth":16,"bounds":{"left":0.4112367,"top":0.11332801,"width":0.06815159,"height":0.023942538},"on_screen":true,"help_text":"","role_description":"text field","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXMenuButton","text":"Filter options","depth":16,"bounds":{"left":0.48238033,"top":0.112529926,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXHeading","text":"File tree","depth":15,"bounds":{"left":0.40026596,"top":0.15083799,"width":0.0003324468,"height":0.0007980846},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"File tree","depth":16,"bounds":{"left":0.40026596,"top":0.15363128,"width":0.014295213,"height":0.0518755},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app","depth":19,"bounds":{"left":0.4162234,"top":0.15682362,"width":0.008144947,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Component/ES","depth":21,"bounds":{"left":0.41888297,"top":0.18276137,"width":0.032081116,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Listeners","depth":23,"bounds":{"left":0.42154256,"top":0.20830008,"width":0.019614361,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"UpdateMultipleTargetsListener.php","depth":25,"bounds":{"left":0.4242021,"top":0.23383878,"width":0.07496676,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"UpdateMultipleTargetsListener.php","depth":26,"bounds":{"left":0.4242021,"top":0.23383878,"width":0.07496676,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"UpdateSingleTargetListener.php","depth":25,"bounds":{"left":0.4242021,"top":0.25937748,"width":0.06865027,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"UpdateSingleTargetListener.php","depth":26,"bounds":{"left":0.4242021,"top":0.25937748,"width":0.06865027,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Processor","depth":23,"bounds":{"left":0.42154256,"top":0.2849162,"width":0.021609042,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Actions","depth":25,"bounds":{"left":0.4242021,"top":0.31085396,"width":0.016123671,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"UpsertDocumentsAction.php","depth":27,"bounds":{"left":0.4268617,"top":0.33639267,"width":0.062333778,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"UpsertDocumentsAction.php","depth":28,"bounds":{"left":0.4268617,"top":0.33639267,"width":0.062333778,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"DTOs","depth":25,"bounds":{"left":0.4242021,"top":0.36193135,"width":0.011968086,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SelectionList.php","depth":27,"bounds":{"left":0.4268617,"top":0.38786912,"width":0.03723404,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"SelectionList.php","depth":28,"bounds":{"left":0.4268617,"top":0.38786912,"width":0.03723404,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Traits","depth":25,"bounds":{"left":0.4242021,"top":0.41340783,"width":0.011968086,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SelectEntityListTrait.php","depth":27,"bounds":{"left":0.4268617,"top":0.43894652,"width":0.05236037,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"SelectEntityListTrait.php","depth":28,"bounds":{"left":0.4268617,"top":0.43894652,"width":0.05236037,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"TargetEntitiesSelector.php","depth":25,"bounds":{"left":0.4242021,"top":0.46448523,"width":0.05668218,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"TargetEntitiesSelector.php","depth":26,"bounds":{"left":0.4242021,"top":0.46448523,"width":0.05668218,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"AsyncUpdateElasticSearch.php","depth":23,"bounds":{"left":0.42154256,"top":0.49002394,"width":0.06732048,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"AsyncUpdateElasticSearch.php","depth":24,"bounds":{"left":0.42154256,"top":0.49002394,"width":0.06732048,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"QueuePriorityEnum.php","depth":23,"bounds":{"left":0.42154256,"top":0.51556265,"width":0.05119681,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"QueuePriorityEnum.php","depth":24,"bounds":{"left":0.42154256,"top":0.51556265,"width":0.05119681,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"UpdateProcessManager.php","depth":23,"bounds":{"left":0.42154256,"top":0.54110134,"width":0.06100399,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"UpdateProcessManager.php","depth":24,"bounds":{"left":0.42154256,"top":0.54110134,"width":0.06100399,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Console/Commands/Elasticsearch","depth":21,"bounds":{"left":0.41888297,"top":0.5666401,"width":0.072972074,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"AsyncUpdateEsEntities.php","depth":23,"bounds":{"left":0.42154256,"top":0.5925778,"width":0.059341755,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"AsyncUpdateEsEntities.php","depth":24,"bounds":{"left":0.42154256,"top":0.5925778,"width":0.059341755,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"ResetAsyncElasticSearchCommand.php","depth":23,"bounds":{"left":0.42154256,"top":0.6181165,"width":0.08577128,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"ResetAsyncElasticSearchCommand.php","depth":24,"bounds":{"left":0.42154256,"top":0.6181165,"width":0.08577128,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"tests/Unit/Component/ES","depth":19,"bounds":{"left":0.4162234,"top":0.64365524,"width":0.05418883,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Collapse file","depth":14,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"app/Component/ES/Listeners/UpdateMultipleTargetsListener.php","depth":15,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXLink","text":"app/Component/ES/Listeners/UpdateMultipleTargetsListener.php","depth":16,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"app/Component/ES/Listeners/UpdateMultipleTargetsListener.php","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy file name to clipboard","depth":15,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Expand all lines: app/Component/ES/Listeners/UpdateMultipleTargetsListener.php","depth":15,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Lines changed: 2 additions & 1 deletion","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Not Viewed","depth":14,"on_screen":false,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Viewed","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Comment on this file","depth":14,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXMenuButton","text":"More options","depth":14,"on_screen":false,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Original file line number","depth":17,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Original file line","depth":17,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Diff line number","depth":17,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Diff line change","depth":17,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"@@ -5,6 +5,7 @@","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"5","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"}]...
|
6532739024298031637
|
-1083670615849345660
|
visual_change
|
accessibility
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
Close tab
New Tab
Customize sidebar
Close Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
AI Chat settings
Close
WORK, Google Account: [EMAIL]
Main menu
New chat
Gemini
PRO
PRO
Conversation with Gemini
Conversation with Gemini
Hi Lukas
Where should we start?
Where should we start?
🖼️ Create image, button, tap to use tool
🖼️ Create image
🎸 Create music, button, tap to use tool
🎸 Create music
Write anything, button, tap to use tool
Write anything
Boost my day, button, tap to use tool
Boost my day
Help me learn, button, tap to use tool
Help me learn
Mak
Mak
Open upload file menu
Tools
Open mode picker
Pro
Send message
Summarize page
Summarize page
Skip to content
Skip to content
Open menu
Homepage (g then d)
jiminny
jiminny
app
app
Search or jump to…
Type
/
to search
Chat with Copilot
Open Copilot…
Create new...
All issues(g then i)
All pull requests
All repositories
You have unread notifications(g then n)
Open user navigation menu
Repository navigation
Repository navigation
Code
Code
Pull requests (31)
Pull requests
(
31
)
Agents
Agents
Actions
Actions
Wiki
Wiki
Security and quality (1)
Security and quality
(
1
)
Insights
Insights
Settings
Settings
Important update
Important update
On April 24 we'll start using GitHub Copilot interaction data for AI model training unless you opt out.
Review this update
Review this update
and manage your preferences in your
GitHub account settings
GitHub account settings
.
Dismiss banner
JY-20808 low priority indexing queue #12082 Edit title
JY-20808 low priority indexing queue
#
12082
Edit title
Preview
Preview
Awaiting approval
Awaiting approval
Code
Code
Open
Vasil-Jiminny
Vasil-Jiminny
wants to merge 36 commits into
master
master
from
JY-20808-low-priority-indexing-queue
JY-20808-low-priority-indexing-queue
Copy head branch name to clipboard
Lines changed: 432 additions & 159 deletions
Conversation (5)
Conversation
(
5
)
Commits (36)
Commits
(
36
)
Checks (3)
Checks
(
3
)
Files changed (18)
Files changed
(
18
)
Pull Request Toolbar
Pull Request Toolbar
Collapse file tree
Open
JY-20808 low priority indexing queue
JY-20808 low priority indexing queue
#
12082
All commits
All commits
Vasil-Jiminny
Vasil-Jiminny
wants to merge 36 commits into
master
master
from
JY-20808-low-priority-indexing-queue
JY-20808-low-priority-indexing-queue
Copy head branch name to clipboard
0 of 18 files viewed
Awaiting approval
Awaiting approval
Submit review
Submit
review
Open diff view settings
Open overview panel
Open comments panel
(
0
)
Filter files…
Filter options
File tree
File tree
app
Component/ES
Listeners
UpdateMultipleTargetsListener.php
UpdateMultipleTargetsListener.php
UpdateSingleTargetListener.php
UpdateSingleTargetListener.php
Processor
Actions
UpsertDocumentsAction.php
UpsertDocumentsAction.php
DTOs
SelectionList.php
SelectionList.php
Traits
SelectEntityListTrait.php
SelectEntityListTrait.php
TargetEntitiesSelector.php
TargetEntitiesSelector.php
AsyncUpdateElasticSearch.php
AsyncUpdateElasticSearch.php
QueuePriorityEnum.php
QueuePriorityEnum.php
UpdateProcessManager.php
UpdateProcessManager.php
Console/Commands/Elasticsearch
AsyncUpdateEsEntities.php
AsyncUpdateEsEntities.php
ResetAsyncElasticSearchCommand.php
ResetAsyncElasticSearchCommand.php
tests/Unit/Component/ES
Collapse file
app/Component/ES/Listeners/UpdateMultipleTargetsListener.php
app/Component/ES/Listeners/UpdateMultipleTargetsListener.php
app/Component/ES/Listeners/UpdateMultipleTargetsListener.php
Copy file name to clipboard
Expand all lines: app/Component/ES/Listeners/UpdateMultipleTargetsListener.php
Lines changed: 2 additions & 1 deletion
Not Viewed
Viewed
Comment on this file
More options
Original file line number
Original file line
Diff line number
Diff line change
@@ -5,6 +5,7 @@
5...
|
55677
|
NULL
|
NULL
|
NULL
|
|
55679
|
1933
|
10
|
2026-05-19T06:39:04.779242+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779172744779_m2.jpg...
|
Firefox
|
JY-20808 low priority indexing queue by Vasil-Jimi JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app — Work...
|
1
|
github.com/jiminny/app/pull/12082/changes#diff-49a github.com/jiminny/app/pull/12082/changes#diff-49a79d99c97caf7fc27ecb1dbacab5a29d871822caa0db0c71e94957c28c87af...
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
Close tab
New Tab
Customize sidebar
Close Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
AI Chat settings
Close
WORK, Google Account: [EMAIL]
Main menu
New chat
Gemini
PRO
PRO
Conversation with Gemini
Conversation with Gemini
Show the uploaded image in a lightbox
Copy prompt
Edit
You said Make a PR of changes Find potential issues and bottlenecks
You said
Make a PR of changes Find potential issues and bottlenecks
Enter a prompt for Gemini
encrypted
Enter a prompt for Gemini
encrypted
Open upload file menu
Tools
Open mode picker
Pro
Stop response
Your Jiminny chats aren’t used to improve our models. Gemini is AI. It can make mistakes, so double check it.
Your privacy & Gemini Opens in a new window
Your privacy & Gemini
Opens in a new window
Gemini is typing
Summarize page
Summarize page
Skip to content
Skip to content
Open menu
Homepage (g then d)
jiminny
jiminny
app
app
Search or jump to…
Type
/
to search
Chat with Copilot
Open Copilot…
Create new...
All issues(g then i)
All pull requests
All repositories
You have unread notifications(g then n)
Open user navigation menu
Repository navigation
Repository navigation
Code
Code
Pull requests (31)
Pull requests
(
31
)
Agents
Agents
Actions
Actions
Wiki
Wiki
Security and quality (1)
Security and quality
(
1
)
Insights
Insights
Settings
Settings
Important update
Important update
On April 24 we'll start using GitHub Copilot interaction data for AI model training unless you opt out.
Review this update
Review this update
and manage your preferences in your
GitHub account settings
GitHub account settings
.
Dismiss banner
JY-20808 low priority indexing queue #12082 Edit title
JY-20808 low priority indexing queue
#
12082
Edit title
Preview
Preview
Awaiting approval
Awaiting approval
Code
Code
Open
Vasil-Jiminny
Vasil-Jiminny
wants to merge 36 commits into
master
master
from
JY-20808-low-priority-indexing-queue
JY-20808-low-priority-indexing-queue
Copy head branch name to clipboard
Lines changed: 432 additions & 159 deletions
Conversation (5)
Conversation
(
5
)
Commits (36)
Commits
(
36
)
Checks (3)
Checks
(
3
)
Files changed (18)
Files changed
(
18
)
Pull Request Toolbar
Pull Request Toolbar
Collapse file tree
Open
JY-20808 low priority indexing queue
JY-20808 low priority indexing queue
#
12082
All commits
All commits
Vasil-Jiminny
Vasil-Jiminny
wants to merge 36 commits into
master
master
from
JY-20808-low-priority-indexing-queue
JY-20808-low-priority-indexing-queue
Copy head branch name to clipboard
0 of 18 files viewed
Awaiting approval
Awaiting approval
Submit review
Submit
review
Open diff view settings
Open overview panel
Open comments panel
(
0
)
Filter files…
Filter options
File tree
File tree
app
Component/ES
Listeners
UpdateMultipleTargetsListener.php
UpdateMultipleTargetsListener.php
UpdateSingleTargetListener.php
UpdateSingleTargetListener.php
Processor
Actions
UpsertDocumentsAction.php
UpsertDocumentsAction.php
DTOs
SelectionList.php
SelectionList.php
Traits
SelectEntityListTrait.php
SelectEntityListTrait.php
TargetEntitiesSelector.php
TargetEntitiesSelector.php
AsyncUpdateElasticSearch.php
AsyncUpdateElasticSearch.php
QueuePriorityEnum.php
QueuePriorityEnum.php
UpdateProcessManager.php
UpdateProcessManager.php
Console/Commands/Elasticsearch
AsyncUpdateEsEntities.php
AsyncUpdateEsEntities.php
ResetAsyncElasticSearchCommand.php
ResetAsyncElasticSearchCommand.php
tests/Unit/Component/ES
Collapse file
app/Component/ES/Listeners/UpdateMultipleTargetsListener.php
app/Component/ES/Listeners/UpdateMultipleTargetsListener.php
app/Component/ES/Listeners/UpdateMultipleTargetsListener.php
Copy file name to clipboard
Expand all lines: app/Component/ES/Listeners/UpdateMultipleTargetsListener.php
Lines changed: 2 additions & 1 deletion
Not Viewed
Viewed
Comment on this file
More options
Original file line number
Original file line
Diff line number
Diff line change
@@ -5,6 +5,7 @@
5
namespace
Jiminny
\
Component
\
ES
\
Listeners
;
5
namespace
Jiminny
\
Component
\
ES
\
Listeners
;
6
6
7
use
Jiminny
\
Component
\
ES
\
AsyncUpdateElasticSearch
;
7
use
Jiminny
\
Component
\
ES
\
AsyncUpdateElasticSearch
;
8
+
use...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira","depth":4,"bounds":{"left":0.0,"top":0.0518755,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.06304868,"width":0.10106383,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app","depth":4,"bounds":{"left":0.0,"top":0.08459697,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app","depth":5,"bounds":{"left":0.013297873,"top":0.09577015,"width":0.18816489,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app","depth":4,"bounds":{"left":0.0,"top":0.11731844,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app","depth":5,"bounds":{"left":0.013297873,"top":0.12849163,"width":0.15674867,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.06732048,"top":0.1245012,"width":0.007978723,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New Tab","depth":4,"bounds":{"left":0.0028257978,"top":0.15163608,"width":0.07413564,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"bounds":{"left":0.0028257978,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Close Google Gemini (⌃X)","depth":6,"bounds":{"left":0.013796543,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Tabs from other devices","depth":6,"bounds":{"left":0.024933511,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"bounds":{"left":0.036070477,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"bounds":{"left":0.04720745,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"AI Chat settings","depth":7,"bounds":{"left":0.35854387,"top":0.055067837,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Close","depth":7,"bounds":{"left":0.37051198,"top":0.055067837,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"WORK, Google Account: lukas.kovalik@jiminny.com","depth":12,"bounds":{"left":0.3678524,"top":0.103751,"width":0.013297873,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Main menu","depth":12,"bounds":{"left":0.08494016,"top":0.103751,"width":0.013297873,"height":0.031923383},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New chat","depth":12,"bounds":{"left":0.09823803,"top":0.10454908,"width":0.028590426,"height":0.030327214},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Gemini","depth":15,"bounds":{"left":0.1008976,"top":0.10973663,"width":0.021941489,"height":0.020351157},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"PRO","depth":11,"bounds":{"left":0.35106382,"top":0.110135674,"width":0.014793883,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"PRO","depth":13,"bounds":{"left":0.3537234,"top":0.112529926,"width":0.009474734,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Conversation with Gemini","depth":15,"bounds":{"left":0.079288565,"top":0.14764565,"width":0.0003324468,"height":0.0007980846},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Conversation with Gemini","depth":16,"bounds":{"left":0.079288565,"top":0.15003991,"width":0.1200133,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Show the uploaded image in a lightbox","depth":20,"bounds":{"left":0.31848404,"top":0.18355946,"width":0.04288564,"height":0.2122905},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy prompt","depth":20,"bounds":{"left":0.17719415,"top":0.40542698,"width":0.013297873,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Edit","depth":20,"bounds":{"left":0.19182181,"top":0.40542698,"width":0.013297873,"height":0.031923383},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"You said Make a PR of changes Find potential issues and bottlenecks","depth":20,"bounds":{"left":0.21176861,"top":0.41181165,"width":0.14428191,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"You said","depth":22,"bounds":{"left":0.079288565,"top":0.41260973,"width":0.019946808,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Make a PR of changes Find potential issues and bottlenecks","depth":22,"bounds":{"left":0.21176861,"top":0.41340783,"width":0.14428191,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXTextArea","text":"Enter a prompt for Gemini\nencrypted","depth":20,"bounds":{"left":0.11469415,"top":0.83439744,"width":0.23670213,"height":0.01915403},"on_screen":true,"value":"Enter a prompt for Gemini\nencrypted","help_text":"","role_description":"text entry area","subrole":"AXUnknown","is_enabled":true,"is_focused":true,"is_selected":false},{"role":"AXStaticText","text":"Enter a prompt for Gemini","depth":21,"bounds":{"left":0.12134308,"top":0.8347965,"width":0.069980055,"height":0.018355945},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"encrypted","depth":21,"bounds":{"left":0.113696806,"top":0.83439744,"width":0.0066489363,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Open upload file menu","depth":20,"bounds":{"left":0.11070479,"top":0.87031126,"width":0.013297873,"height":0.031923383},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Tools","depth":18,"bounds":{"left":0.12666224,"top":0.87031126,"width":0.013297873,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Open mode picker","depth":20,"bounds":{"left":0.31399602,"top":0.867917,"width":0.026097074,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pro","depth":23,"bounds":{"left":0.31931517,"top":0.87669593,"width":0.007480053,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Stop response","depth":19,"bounds":{"left":0.3414229,"top":0.8671189,"width":0.013962766,"height":0.033519555},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Your Jiminny chats aren’t used to improve our models. Gemini is AI. It can make mistakes, so double check it.","depth":17,"bounds":{"left":0.11303192,"top":0.92178774,"width":0.19996676,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Your privacy & Gemini Opens in a new window","depth":17,"bounds":{"left":0.31299868,"top":0.92178774,"width":0.040059842,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Your privacy & Gemini","depth":18,"bounds":{"left":0.31299868,"top":0.92178774,"width":0.040059842,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Opens in a new window","depth":19,"bounds":{"left":0.079288565,"top":0.92098963,"width":0.043218084,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Gemini is typing","depth":9,"bounds":{"left":0.079288565,"top":0.091380686,"width":0.035738032,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Summarize page","depth":7,"bounds":{"left":0.08494016,"top":0.95730245,"width":0.053523935,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Summarize page","depth":9,"bounds":{"left":0.09059176,"top":0.96249,"width":0.042220745,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Skip to content","depth":6,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip to content","depth":7,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Open menu","depth":10,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Homepage (g then d)","depth":9,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"jiminny","depth":12,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"jiminny","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"app","depth":12,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"app","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Search or jump to…","depth":9,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Type","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"to search","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Chat with Copilot","depth":10,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXMenuButton","text":"Open Copilot…","depth":9,"on_screen":false,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXMenuButton","text":"Create new...","depth":9,"on_screen":false,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"All issues(g then i)","depth":9,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"All pull requests","depth":9,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"All repositories","depth":9,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"You have unread notifications(g then n)","depth":9,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Open user navigation menu","depth":9,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"Repository navigation","depth":9,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Repository navigation","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Code","depth":12,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Code","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Pull requests (31)","depth":12,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pull requests","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"31","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Agents","depth":12,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Agents","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Actions","depth":12,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Actions","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Wiki","depth":12,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Wiki","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Security and quality (1)","depth":12,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Security and quality","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Insights","depth":12,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Insights","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Settings","depth":12,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Settings","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Important update","depth":10,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Important update","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"On April 24 we'll start using GitHub Copilot interaction data for AI model training unless you opt out.","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review this update","depth":10,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review this update","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"and manage your preferences in your","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"GitHub account settings","depth":10,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"GitHub account settings","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":".","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Dismiss banner","depth":9,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"JY-20808 low priority indexing queue #12082 Edit title","depth":13,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"JY-20808 low priority indexing queue","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"12082","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Edit title","depth":14,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXMenuButton","text":"Preview","depth":13,"on_screen":false,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Preview","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Awaiting approval","depth":13,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Awaiting approval","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Code","depth":13,"on_screen":false,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Code","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Open","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Vasil-Jiminny","depth":15,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Vasil-Jiminny","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"wants to merge 36 commits into","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"master","depth":15,"on_screen":false,"role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"master","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"from","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"JY-20808-low-priority-indexing-queue","depth":16,"on_screen":false,"role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20808-low-priority-indexing-queue","depth":17,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy head branch name to clipboard","depth":16,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Lines changed: 432 additions & 159 deletions","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Conversation (5)","depth":16,"on_screen":false,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Conversation","depth":17,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"5","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Commits (36)","depth":16,"on_screen":false,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Commits","depth":17,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"36","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Checks (3)","depth":16,"on_screen":false,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Checks","depth":17,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Files changed (18)","depth":16,"on_screen":false,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"Files changed","depth":17,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"18","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Pull Request Toolbar","depth":14,"bounds":{"left":0.39993352,"top":0.075019956,"width":0.0003324468,"height":0.0007980846},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Pull Request Toolbar","depth":15,"bounds":{"left":0.39993352,"top":0.077813245,"width":0.030086435,"height":0.08060654},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Collapse file tree","depth":14,"bounds":{"left":0.39993352,"top":0.06424581,"width":0.00930851,"height":0.022346368},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXStaticText","text":"Open","depth":14,"bounds":{"left":0.4225399,"top":0.06863528,"width":0.011968086,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"JY-20808 low priority indexing queue","depth":14,"bounds":{"left":0.44115692,"top":0.057462092,"width":0.084773935,"height":0.016759777},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20808 low priority indexing queue","depth":16,"bounds":{"left":0.44115692,"top":0.05905826,"width":0.084773935,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#","depth":15,"bounds":{"left":0.52859044,"top":0.05905826,"width":0.0029920214,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"12082","depth":15,"bounds":{"left":0.5315825,"top":0.05905826,"width":0.013464096,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"All commits","depth":14,"bounds":{"left":0.43849733,"top":0.07102953,"width":0.03374335,"height":0.022346368},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"All commits","depth":16,"bounds":{"left":0.44148937,"top":0.07621708,"width":0.02244016,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Vasil-Jiminny","depth":15,"bounds":{"left":0.4765625,"top":0.075019956,"width":0.02642952,"height":0.014365523},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Vasil-Jiminny","depth":16,"bounds":{"left":0.4765625,"top":0.07621708,"width":0.02642952,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"wants to merge 36 commits into","depth":15,"bounds":{"left":0.5043218,"top":0.07621708,"width":0.06050532,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"master","depth":15,"bounds":{"left":0.5661569,"top":0.07342378,"width":0.018450798,"height":0.017557861},"on_screen":true,"role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"master","depth":16,"bounds":{"left":0.5681516,"top":0.07661612,"width":0.014461436,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"from","depth":16,"bounds":{"left":0.5859375,"top":0.07621708,"width":0.008643617,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"JY-20808-low-priority-indexing-queue","depth":16,"bounds":{"left":0.5959109,"top":0.07342378,"width":0.09042553,"height":0.017557861},"on_screen":true,"role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20808-low-priority-indexing-queue","depth":17,"bounds":{"left":0.5979056,"top":0.07661612,"width":0.08643617,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy head branch name to clipboard","depth":16,"bounds":{"left":0.68766624,"top":0.07102953,"width":0.00930851,"height":0.022346368},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"0 of 18 files viewed","depth":15,"bounds":{"left":0.81366354,"top":0.07661612,"width":0.01512633,"height":0.08060654},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Awaiting approval","depth":14,"bounds":{"left":0.85355717,"top":0.06424581,"width":0.04654255,"height":0.022346368},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Awaiting approval","depth":16,"bounds":{"left":0.86319816,"top":0.06943336,"width":0.033909574,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Submit review","depth":14,"bounds":{"left":0.9027593,"top":0.06424581,"width":0.03856383,"height":0.022346368},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Submit","depth":16,"bounds":{"left":0.90575135,"top":0.06943336,"width":0.014793883,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"review","depth":16,"bounds":{"left":0.9205452,"top":0.06943336,"width":0.012466756,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Open diff view settings","depth":14,"bounds":{"left":0.9439827,"top":0.06424581,"width":0.00930851,"height":0.022346368},"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Open overview panel","depth":14,"bounds":{"left":0.9616024,"top":0.06424581,"width":0.00930851,"height":0.022346368},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Open comments panel","depth":14,"bounds":{"left":0.9722407,"top":0.06424581,"width":0.017287234,"height":0.022346368},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"(","depth":16,"bounds":{"left":0.98055184,"top":0.06943336,"width":0.0026595744,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"0","depth":16,"bounds":{"left":0.98321146,"top":0.06943336,"width":0.0026595744,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")","depth":16,"bounds":{"left":0.985871,"top":0.06943336,"width":0.0014960107,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXTextField","text":"Filter files…","depth":16,"bounds":{"left":0.4112367,"top":0.11332801,"width":0.06815159,"height":0.023942538},"on_screen":true,"help_text":"","role_description":"text field","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXMenuButton","text":"Filter options","depth":16,"bounds":{"left":0.48238033,"top":0.112529926,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXHeading","text":"File tree","depth":15,"bounds":{"left":0.40026596,"top":0.15083799,"width":0.0003324468,"height":0.0007980846},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"File tree","depth":16,"bounds":{"left":0.40026596,"top":0.15363128,"width":0.014295213,"height":0.0518755},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app","depth":19,"bounds":{"left":0.4162234,"top":0.15682362,"width":0.008144947,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Component/ES","depth":21,"bounds":{"left":0.41888297,"top":0.18276137,"width":0.032081116,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Listeners","depth":23,"bounds":{"left":0.42154256,"top":0.20830008,"width":0.019614361,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"UpdateMultipleTargetsListener.php","depth":25,"bounds":{"left":0.4242021,"top":0.23383878,"width":0.07496676,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"UpdateMultipleTargetsListener.php","depth":26,"bounds":{"left":0.4242021,"top":0.23383878,"width":0.07496676,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"UpdateSingleTargetListener.php","depth":25,"bounds":{"left":0.4242021,"top":0.25937748,"width":0.06865027,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"UpdateSingleTargetListener.php","depth":26,"bounds":{"left":0.4242021,"top":0.25937748,"width":0.06865027,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Processor","depth":23,"bounds":{"left":0.42154256,"top":0.2849162,"width":0.021609042,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Actions","depth":25,"bounds":{"left":0.4242021,"top":0.31085396,"width":0.016123671,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"UpsertDocumentsAction.php","depth":27,"bounds":{"left":0.4268617,"top":0.33639267,"width":0.062333778,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"UpsertDocumentsAction.php","depth":28,"bounds":{"left":0.4268617,"top":0.33639267,"width":0.062333778,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"DTOs","depth":25,"bounds":{"left":0.4242021,"top":0.36193135,"width":0.011968086,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SelectionList.php","depth":27,"bounds":{"left":0.4268617,"top":0.38786912,"width":0.03723404,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"SelectionList.php","depth":28,"bounds":{"left":0.4268617,"top":0.38786912,"width":0.03723404,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Traits","depth":25,"bounds":{"left":0.4242021,"top":0.41340783,"width":0.011968086,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SelectEntityListTrait.php","depth":27,"bounds":{"left":0.4268617,"top":0.43894652,"width":0.05236037,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"SelectEntityListTrait.php","depth":28,"bounds":{"left":0.4268617,"top":0.43894652,"width":0.05236037,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"TargetEntitiesSelector.php","depth":25,"bounds":{"left":0.4242021,"top":0.46448523,"width":0.05668218,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"TargetEntitiesSelector.php","depth":26,"bounds":{"left":0.4242021,"top":0.46448523,"width":0.05668218,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"AsyncUpdateElasticSearch.php","depth":23,"bounds":{"left":0.42154256,"top":0.49002394,"width":0.06732048,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"AsyncUpdateElasticSearch.php","depth":24,"bounds":{"left":0.42154256,"top":0.49002394,"width":0.06732048,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"QueuePriorityEnum.php","depth":23,"bounds":{"left":0.42154256,"top":0.51556265,"width":0.05119681,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"QueuePriorityEnum.php","depth":24,"bounds":{"left":0.42154256,"top":0.51556265,"width":0.05119681,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"UpdateProcessManager.php","depth":23,"bounds":{"left":0.42154256,"top":0.54110134,"width":0.06100399,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"UpdateProcessManager.php","depth":24,"bounds":{"left":0.42154256,"top":0.54110134,"width":0.06100399,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Console/Commands/Elasticsearch","depth":21,"bounds":{"left":0.41888297,"top":0.5666401,"width":0.072972074,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"AsyncUpdateEsEntities.php","depth":23,"bounds":{"left":0.42154256,"top":0.5925778,"width":0.059341755,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"AsyncUpdateEsEntities.php","depth":24,"bounds":{"left":0.42154256,"top":0.5925778,"width":0.059341755,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"ResetAsyncElasticSearchCommand.php","depth":23,"bounds":{"left":0.42154256,"top":0.6181165,"width":0.08577128,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"ResetAsyncElasticSearchCommand.php","depth":24,"bounds":{"left":0.42154256,"top":0.6181165,"width":0.08577128,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"tests/Unit/Component/ES","depth":19,"bounds":{"left":0.4162234,"top":0.64365524,"width":0.05418883,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Collapse file","depth":14,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"app/Component/ES/Listeners/UpdateMultipleTargetsListener.php","depth":15,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXLink","text":"app/Component/ES/Listeners/UpdateMultipleTargetsListener.php","depth":16,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"app/Component/ES/Listeners/UpdateMultipleTargetsListener.php","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy file name to clipboard","depth":15,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Expand all lines: app/Component/ES/Listeners/UpdateMultipleTargetsListener.php","depth":15,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Lines changed: 2 additions & 1 deletion","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Not Viewed","depth":14,"on_screen":false,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Viewed","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Comment on this file","depth":14,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXMenuButton","text":"More options","depth":14,"on_screen":false,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Original file line number","depth":17,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Original file line","depth":17,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Diff line number","depth":17,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Diff line change","depth":17,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"@@ -5,6 +5,7 @@","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"5","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"namespace","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Jiminny","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\\","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Component","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\\","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ES","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\\","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Listeners","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":";","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"5","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"namespace","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Jiminny","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\\","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Component","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\\","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ES","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\\","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Listeners","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":";","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"6","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"6","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"7","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Jiminny","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\\","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Component","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\\","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ES","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\\","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AsyncUpdateElasticSearch","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":";","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"7","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Jiminny","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\\","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Component","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\\","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ES","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\\","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AsyncUpdateElasticSearch","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":";","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"8","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"+","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"}]...
|
-7291629655760133156
|
-441344718965744252
|
visual_change
|
accessibility
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
Close tab
New Tab
Customize sidebar
Close Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
AI Chat settings
Close
WORK, Google Account: [EMAIL]
Main menu
New chat
Gemini
PRO
PRO
Conversation with Gemini
Conversation with Gemini
Show the uploaded image in a lightbox
Copy prompt
Edit
You said Make a PR of changes Find potential issues and bottlenecks
You said
Make a PR of changes Find potential issues and bottlenecks
Enter a prompt for Gemini
encrypted
Enter a prompt for Gemini
encrypted
Open upload file menu
Tools
Open mode picker
Pro
Stop response
Your Jiminny chats aren’t used to improve our models. Gemini is AI. It can make mistakes, so double check it.
Your privacy & Gemini Opens in a new window
Your privacy & Gemini
Opens in a new window
Gemini is typing
Summarize page
Summarize page
Skip to content
Skip to content
Open menu
Homepage (g then d)
jiminny
jiminny
app
app
Search or jump to…
Type
/
to search
Chat with Copilot
Open Copilot…
Create new...
All issues(g then i)
All pull requests
All repositories
You have unread notifications(g then n)
Open user navigation menu
Repository navigation
Repository navigation
Code
Code
Pull requests (31)
Pull requests
(
31
)
Agents
Agents
Actions
Actions
Wiki
Wiki
Security and quality (1)
Security and quality
(
1
)
Insights
Insights
Settings
Settings
Important update
Important update
On April 24 we'll start using GitHub Copilot interaction data for AI model training unless you opt out.
Review this update
Review this update
and manage your preferences in your
GitHub account settings
GitHub account settings
.
Dismiss banner
JY-20808 low priority indexing queue #12082 Edit title
JY-20808 low priority indexing queue
#
12082
Edit title
Preview
Preview
Awaiting approval
Awaiting approval
Code
Code
Open
Vasil-Jiminny
Vasil-Jiminny
wants to merge 36 commits into
master
master
from
JY-20808-low-priority-indexing-queue
JY-20808-low-priority-indexing-queue
Copy head branch name to clipboard
Lines changed: 432 additions & 159 deletions
Conversation (5)
Conversation
(
5
)
Commits (36)
Commits
(
36
)
Checks (3)
Checks
(
3
)
Files changed (18)
Files changed
(
18
)
Pull Request Toolbar
Pull Request Toolbar
Collapse file tree
Open
JY-20808 low priority indexing queue
JY-20808 low priority indexing queue
#
12082
All commits
All commits
Vasil-Jiminny
Vasil-Jiminny
wants to merge 36 commits into
master
master
from
JY-20808-low-priority-indexing-queue
JY-20808-low-priority-indexing-queue
Copy head branch name to clipboard
0 of 18 files viewed
Awaiting approval
Awaiting approval
Submit review
Submit
review
Open diff view settings
Open overview panel
Open comments panel
(
0
)
Filter files…
Filter options
File tree
File tree
app
Component/ES
Listeners
UpdateMultipleTargetsListener.php
UpdateMultipleTargetsListener.php
UpdateSingleTargetListener.php
UpdateSingleTargetListener.php
Processor
Actions
UpsertDocumentsAction.php
UpsertDocumentsAction.php
DTOs
SelectionList.php
SelectionList.php
Traits
SelectEntityListTrait.php
SelectEntityListTrait.php
TargetEntitiesSelector.php
TargetEntitiesSelector.php
AsyncUpdateElasticSearch.php
AsyncUpdateElasticSearch.php
QueuePriorityEnum.php
QueuePriorityEnum.php
UpdateProcessManager.php
UpdateProcessManager.php
Console/Commands/Elasticsearch
AsyncUpdateEsEntities.php
AsyncUpdateEsEntities.php
ResetAsyncElasticSearchCommand.php
ResetAsyncElasticSearchCommand.php
tests/Unit/Component/ES
Collapse file
app/Component/ES/Listeners/UpdateMultipleTargetsListener.php
app/Component/ES/Listeners/UpdateMultipleTargetsListener.php
app/Component/ES/Listeners/UpdateMultipleTargetsListener.php
Copy file name to clipboard
Expand all lines: app/Component/ES/Listeners/UpdateMultipleTargetsListener.php
Lines changed: 2 additions & 1 deletion
Not Viewed
Viewed
Comment on this file
More options
Original file line number
Original file line
Diff line number
Diff line change
@@ -5,6 +5,7 @@
5
namespace
Jiminny
\
Component
\
ES
\
Listeners
;
5
namespace
Jiminny
\
Component
\
ES
\
Listeners
;
6
6
7
use
Jiminny
\
Component
\
ES
\
AsyncUpdateElasticSearch
;
7
use
Jiminny
\
Component
\
ES
\
AsyncUpdateElasticSearch
;
8
+
use...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
55680
|
1932
|
8
|
2026-05-19T06:39:16.377647+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779172756377_m1.jpg...
|
Firefox
|
JY-20808 low priority indexing queue by Vasil-Jimi JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app — Work...
|
1
|
github.com/jiminny/app/pull/12082/changes#diff-49a github.com/jiminny/app/pull/12082/changes#diff-49a79d99c97caf7fc27ecb1dbacab5a29d871822caa0db0c71e94957c28c87af...
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
Close tab
New Tab
Customize sidebar
Close Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
AI Chat settings
Close
WORK, Google Account: [EMAIL]
Main menu
New chat
Gemini
New Chat
Open menu for conversation actions.
Conversation with Gemini
Conversation with Gemini
Show the uploaded image in a lightbox
Copy prompt
Edit
You said Make a PR of changes Find potential issues and bottlenecks
You said
Make a PR of changes Find potential issues and bottlenecks
Show thinking
Gemini said
Gemini said
I can see you've uploaded a screenshot of a code diff,
likely from a version control system given the red and green highlights.
I would love to help you review the changes,
spot bottlenecks,
and help you draft a Pull Request.
However,
the image resolution is far too low for me to read.
It appears to be a completely zoomed-out view where the code has been reduced to tiny,
illegible pixels.
Because of this,
I cannot extract any text or logic to analyze.
How You Can Share the Code
How You Can Share the Code
To help me review your code effectively,
Enter a prompt for Gemini
encrypted
Enter a prompt for Gemini
encrypted
Open upload file menu
Tools
Open mode picker
Pro
Stop response
Your Jiminny chats aren’t used to improve our models. Gemini is AI. It can make mistakes, so double check it.
Your privacy & Gemini Opens in a new window
Your privacy & Gemini
Opens in a new window
Summarize page
Summarize page
Skip to content
Skip to content
Open menu
Homepage (g then d)
jiminny
jiminny
app
app
Search or jump to…
Type
/
to search
Chat with Copilot
Open Copilot…
Create new...
All issues(g then i)
All pull requests
All repositories
You have unread notifications(g then n)
Open user navigation menu
Repository navigation
Repository navigation
Code
Code
Pull requests (31)
Pull requests
(
31
)
Agents
Agents
Actions
Actions
Wiki
Wiki
Security and quality (1)
Security and quality
(
1
)
Insights
Insights
Settings
Settings
Important update
Important update
On April 24 we'll start using GitHub Copilot interaction data for AI model training unless you opt out.
Review this update
Review this update
and manage your preferences in your
GitHub account settings
GitHub account settings
.
Dismiss banner
JY-20808 low priority indexing queue #12082 Edit title
JY-20808 low priority indexing queue
#
12082
Edit title
Preview
Preview
Awaiting approval
Awaiting approval
Code
Code
Open
Vasil-Jiminny
Vasil-Jiminny
wants to merge 36 commits into
master
master
from
JY-20808-low-priority-indexing-queue
JY-20808-low-priority-indexing-queue
Copy head branch name to clipboard
Lines changed: 432 additions & 159 deletions
Conversation (5)
Conversation
(
5
)
Commits (36)
Commits
(
36
)
Checks (3)
Checks
(
3
)
Files changed (18)
Files changed
(
18
)
Pull Request Toolbar
Pull Request Toolbar
Collapse file tree
Open
JY-20808 low priority indexing queue
JY-20808 low priority indexing queue
#
12082
All commits
All commits
Vasil-Jiminny
Vasil-Jiminny
wants to merge 36 commits into
master
master
from
JY-20808-low-priority-indexing-queue
JY-20808-low-priority-indexing-queue
Copy head branch name to clipboard
0 of 18 files viewed
Awaiting approval
Awaiting approval
Submit review
Submit
review
Open diff view settings
Open overview panel
Open comments panel
(
0
)
Filter files…
Filter options
File tree
File tree
app
Component/ES
Listeners
UpdateMultipleTargetsListener.php
UpdateMultipleTargetsListener.php
UpdateSingleTargetListener.php
UpdateSingleTargetListener.php
Processor
Actions
UpsertDocumentsAction.php
UpsertDocumentsAction.php
DTOs
SelectionList.php
SelectionList.php
Traits
SelectEntityListTrait.php
SelectEntityListTrait.php
TargetEntitiesSelector.php
TargetEntitiesSelector.php
AsyncUpdateElasticSearch.php
AsyncUpdateElasticSearch.php
QueuePriorityEnum.php
QueuePriorityEnum.php
UpdateProcessManager.php...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New Tab","depth":4,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Close Google Gemini (⌃X)","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Tabs from other devices","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"AI Chat settings","depth":7,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Close","depth":7,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"WORK, Google Account: lukas.kovalik@jiminny.com","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Main menu","depth":12,"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New chat","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Gemini","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"New Chat","depth":12,"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Open menu for conversation actions.","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXHeading","text":"Conversation with Gemini","depth":15,"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Conversation with Gemini","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Show the uploaded image in a lightbox","depth":21,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy prompt","depth":21,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Edit","depth":21,"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"You said Make a PR of changes Find potential issues and bottlenecks","depth":21,"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"You said","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Make a PR of changes Find potential issues and bottlenecks","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Show thinking","depth":25,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Gemini said","depth":20,"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Gemini said","depth":21,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"I can see you've uploaded a screenshot of a code diff,","depth":24,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"likely from a version control system given the red and green highlights.","depth":24,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"I would love to help you review the changes,","depth":24,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"spot bottlenecks,","depth":24,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"and help you draft a Pull Request.","depth":24,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"However,","depth":24,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"the image resolution is far too low for me to read.","depth":24,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"It appears to be a completely zoomed-out view where the code has been reduced to tiny,","depth":24,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"illegible pixels.","depth":24,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Because of this,","depth":24,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"I cannot extract any text or logic to analyze.","depth":24,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"How You Can Share the Code","depth":23,"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"How You Can Share the Code","depth":24,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"To help me review your code effectively,","depth":24,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXTextArea","text":"Enter a prompt for Gemini\nencrypted","depth":20,"on_screen":true,"value":"Enter a prompt for Gemini\nencrypted","help_text":"","role_description":"text entry area","subrole":"AXUnknown","is_enabled":true,"is_focused":true,"is_selected":false},{"role":"AXStaticText","text":"Enter a prompt for Gemini","depth":21,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"encrypted","depth":21,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Open upload file menu","depth":20,"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Tools","depth":18,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Open mode picker","depth":20,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pro","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Stop response","depth":19,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Your Jiminny chats aren’t used to improve our models. Gemini is AI. It can make mistakes, so double check it.","depth":17,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Your privacy & Gemini Opens in a new window","depth":17,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Your privacy & Gemini","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Opens in a new window","depth":19,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Summarize page","depth":7,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Summarize page","depth":9,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Skip to content","depth":6,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip to content","depth":7,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Open menu","depth":10,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Homepage (g then d)","depth":9,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"jiminny","depth":12,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"jiminny","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"app","depth":12,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"app","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Search or jump to…","depth":9,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Type","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"to search","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Chat with Copilot","depth":10,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXMenuButton","text":"Open Copilot…","depth":9,"on_screen":false,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXMenuButton","text":"Create new...","depth":9,"on_screen":false,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"All issues(g then i)","depth":9,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"All pull requests","depth":9,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"All repositories","depth":9,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"You have unread notifications(g then n)","depth":9,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Open user navigation menu","depth":9,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"Repository navigation","depth":9,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Repository navigation","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Code","depth":12,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Code","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Pull requests (31)","depth":12,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pull requests","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"31","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Agents","depth":12,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Agents","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Actions","depth":12,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Actions","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Wiki","depth":12,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Wiki","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Security and quality (1)","depth":12,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Security and quality","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Insights","depth":12,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Insights","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Settings","depth":12,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Settings","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Important update","depth":10,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Important update","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"On April 24 we'll start using GitHub Copilot interaction data for AI model training unless you opt out.","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review this update","depth":10,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review this update","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"and manage your preferences in your","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"GitHub account settings","depth":10,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"GitHub account settings","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":".","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Dismiss banner","depth":9,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"JY-20808 low priority indexing queue #12082 Edit title","depth":13,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"JY-20808 low priority indexing queue","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"12082","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Edit title","depth":14,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXMenuButton","text":"Preview","depth":13,"on_screen":false,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Preview","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Awaiting approval","depth":13,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Awaiting approval","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Code","depth":13,"on_screen":false,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Code","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Open","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Vasil-Jiminny","depth":15,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Vasil-Jiminny","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"wants to merge 36 commits into","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"master","depth":15,"on_screen":false,"role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"master","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"from","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"JY-20808-low-priority-indexing-queue","depth":16,"on_screen":false,"role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20808-low-priority-indexing-queue","depth":17,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy head branch name to clipboard","depth":16,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Lines changed: 432 additions & 159 deletions","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Conversation (5)","depth":16,"on_screen":false,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Conversation","depth":17,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"5","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Commits (36)","depth":16,"on_screen":false,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Commits","depth":17,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"36","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Checks (3)","depth":16,"on_screen":false,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Checks","depth":17,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Files changed (18)","depth":16,"on_screen":false,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"Files changed","depth":17,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"18","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Pull Request Toolbar","depth":14,"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Pull Request Toolbar","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Collapse file tree","depth":14,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXStaticText","text":"Open","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"JY-20808 low priority indexing queue","depth":14,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20808 low priority indexing queue","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"12082","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"All commits","depth":14,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"All commits","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Vasil-Jiminny","depth":15,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Vasil-Jiminny","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"wants to merge 36 commits into","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"master","depth":15,"on_screen":true,"role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"master","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"from","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"JY-20808-low-priority-indexing-queue","depth":16,"on_screen":true,"role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20808-low-priority-indexing-queue","depth":17,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy head branch name to clipboard","depth":16,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"0 of 18 files viewed","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Awaiting approval","depth":14,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Awaiting approval","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Submit review","depth":14,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Submit","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"review","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Open diff view settings","depth":14,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Open overview panel","depth":14,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Open comments panel","depth":14,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"(","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"0","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXTextField","text":"Filter files…","depth":16,"on_screen":true,"help_text":"","role_description":"text field","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXMenuButton","text":"Filter options","depth":16,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXHeading","text":"File tree","depth":15,"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"File tree","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app","depth":19,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Component/ES","depth":21,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Listeners","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"UpdateMultipleTargetsListener.php","depth":25,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"UpdateMultipleTargetsListener.php","depth":26,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"UpdateSingleTargetListener.php","depth":25,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"UpdateSingleTargetListener.php","depth":26,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Processor","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Actions","depth":25,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"UpsertDocumentsAction.php","depth":27,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"UpsertDocumentsAction.php","depth":28,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"DTOs","depth":25,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SelectionList.php","depth":27,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"SelectionList.php","depth":28,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Traits","depth":25,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SelectEntityListTrait.php","depth":27,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"SelectEntityListTrait.php","depth":28,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"TargetEntitiesSelector.php","depth":25,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"TargetEntitiesSelector.php","depth":26,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"AsyncUpdateElasticSearch.php","depth":23,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"AsyncUpdateElasticSearch.php","depth":24,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"QueuePriorityEnum.php","depth":23,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"QueuePriorityEnum.php","depth":24,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"UpdateProcessManager.php","depth":23,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false}]...
|
-3944318445736407668
|
-508265386088833586
|
idle
|
accessibility
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
Close tab
New Tab
Customize sidebar
Close Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
AI Chat settings
Close
WORK, Google Account: [EMAIL]
Main menu
New chat
Gemini
New Chat
Open menu for conversation actions.
Conversation with Gemini
Conversation with Gemini
Show the uploaded image in a lightbox
Copy prompt
Edit
You said Make a PR of changes Find potential issues and bottlenecks
You said
Make a PR of changes Find potential issues and bottlenecks
Show thinking
Gemini said
Gemini said
I can see you've uploaded a screenshot of a code diff,
likely from a version control system given the red and green highlights.
I would love to help you review the changes,
spot bottlenecks,
and help you draft a Pull Request.
However,
the image resolution is far too low for me to read.
It appears to be a completely zoomed-out view where the code has been reduced to tiny,
illegible pixels.
Because of this,
I cannot extract any text or logic to analyze.
How You Can Share the Code
How You Can Share the Code
To help me review your code effectively,
Enter a prompt for Gemini
encrypted
Enter a prompt for Gemini
encrypted
Open upload file menu
Tools
Open mode picker
Pro
Stop response
Your Jiminny chats aren’t used to improve our models. Gemini is AI. It can make mistakes, so double check it.
Your privacy & Gemini Opens in a new window
Your privacy & Gemini
Opens in a new window
Summarize page
Summarize page
Skip to content
Skip to content
Open menu
Homepage (g then d)
jiminny
jiminny
app
app
Search or jump to…
Type
/
to search
Chat with Copilot
Open Copilot…
Create new...
All issues(g then i)
All pull requests
All repositories
You have unread notifications(g then n)
Open user navigation menu
Repository navigation
Repository navigation
Code
Code
Pull requests (31)
Pull requests
(
31
)
Agents
Agents
Actions
Actions
Wiki
Wiki
Security and quality (1)
Security and quality
(
1
)
Insights
Insights
Settings
Settings
Important update
Important update
On April 24 we'll start using GitHub Copilot interaction data for AI model training unless you opt out.
Review this update
Review this update
and manage your preferences in your
GitHub account settings
GitHub account settings
.
Dismiss banner
JY-20808 low priority indexing queue #12082 Edit title
JY-20808 low priority indexing queue
#
12082
Edit title
Preview
Preview
Awaiting approval
Awaiting approval
Code
Code
Open
Vasil-Jiminny
Vasil-Jiminny
wants to merge 36 commits into
master
master
from
JY-20808-low-priority-indexing-queue
JY-20808-low-priority-indexing-queue
Copy head branch name to clipboard
Lines changed: 432 additions & 159 deletions
Conversation (5)
Conversation
(
5
)
Commits (36)
Commits
(
36
)
Checks (3)
Checks
(
3
)
Files changed (18)
Files changed
(
18
)
Pull Request Toolbar
Pull Request Toolbar
Collapse file tree
Open
JY-20808 low priority indexing queue
JY-20808 low priority indexing queue
#
12082
All commits
All commits
Vasil-Jiminny
Vasil-Jiminny
wants to merge 36 commits into
master
master
from
JY-20808-low-priority-indexing-queue
JY-20808-low-priority-indexing-queue
Copy head branch name to clipboard
0 of 18 files viewed
Awaiting approval
Awaiting approval
Submit review
Submit
review
Open diff view settings
Open overview panel
Open comments panel
(
0
)
Filter files…
Filter options
File tree
File tree
app
Component/ES
Listeners
UpdateMultipleTargetsListener.php
UpdateMultipleTargetsListener.php
UpdateSingleTargetListener.php
UpdateSingleTargetListener.php
Processor
Actions
UpsertDocumentsAction.php
UpsertDocumentsAction.php
DTOs
SelectionList.php
SelectionList.php
Traits
SelectEntityListTrait.php
SelectEntityListTrait.php
TargetEntitiesSelector.php
TargetEntitiesSelector.php
AsyncUpdateElasticSearch.php
AsyncUpdateElasticSearch.php
QueuePriorityEnum.php
QueuePriorityEnum.php
UpdateProcessManager.php...
|
55676
|
NULL
|
NULL
|
NULL
|
|
55681
|
1933
|
11
|
2026-05-19T06:39:35.044961+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779172775044_m2.jpg...
|
Firefox
|
JY-20808 low priority indexing queue by Vasil-Jimi JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app — Work...
|
1
|
github.com/jiminny/app/pull/12082/changes#diff-49a github.com/jiminny/app/pull/12082/changes#diff-49a79d99c97caf7fc27ecb1dbacab5a29d871822caa0db0c71e94957c28c87af...
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
Close tab
New Tab
Customize sidebar
Close Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
AI Chat settings
Close
WORK, Google Account: [EMAIL]
Main menu
New chat
Gemini
New Chat
Open menu for conversation actions.
Conversation with Gemini
Conversation with Gemini
Show the uploaded image in a lightbox
Copy prompt
Edit
You said Make a PR of changes Find potential issues and bottlenecks
You said
Make a PR of changes Find potential issues and bottlenecks
Listen
Show thinking
Gemini said
Gemini said
I can see you've uploaded a screenshot of a code diff, likely from a version control system given the red and green highlights. I would love to help you review the changes, spot bottlenecks, and help you draft a Pull Request.
However,
the image resolution is far too low for me to read.
It appears to be a completely zoomed-out view where the code has been reduced to tiny, illegible pixels. Because of this, I cannot extract any text or logic to analyze.
How You Can Share the Code
How You Can Share the Code
To help me review your code effectively, please try one of the following:
Paste the text directly:
Copy the specific code blocks (both the old and new versions if possible) and paste them directly into our chat.
Upload the files:
If the changes are extensive, you can upload the raw text or code files.
Take high-resolution screenshots:
If you must use images, take closer, readable screenshots of the specific functions or methods you want me to review.
Once you provide the readable code, I can dive right in to identify potential bugs, assess performance bottlenecks, and help you summarize the changes for your PR!
Good response
Bad response
Redo
Share & export
Copy
Show more options
Enter a prompt for Gemini
encrypted
Enter a prompt for Gemini
encrypted
Open upload file menu
Tools
Open mode picker
Pro
Microphone
Send message
Your Jiminny chats aren’t used to improve our models. Gemini is AI. It can make mistakes, so double check it.
Your privacy & Gemini Opens in a new window
Your privacy & Gemini
Opens in a new window
Summarize page
Summarize page
Skip to content
Skip to content
Open menu
Homepage (g then d)
jiminny
jiminny
app
app
Search or jump to…
Type
/
to search
Chat with Copilot
Open Copilot…
Create new...
All issues(g then i)
All pull requests
All repositories
You have unread notifications(g then n)
Open user navigation menu
Repository navigation
Repository navigation
Code
Code
Pull requests (31)
Pull requests
(
31
)
Agents
Agents
Actions
Actions
Wiki
Wiki
Security and quality (1)
Security and quality
(
1
)
Insights
Insights
Settings
Settings
Important update
Important update
On April 24 we'll start using GitHub Copilot interaction data for AI model training unless you opt out.
Review this update
Review this update
and manage your preferences in your
GitHub account settings
GitHub account settings
.
Dismiss banner
JY-20808 low priority indexing queue #12082 Edit title
JY-20808 low priority indexing queue
#
12082
Edit title
Preview
Preview
Awaiting approval
Awaiting approval
Code
Code
Open
Vasil-Jiminny
Vasil-Jiminny
wants to merge 36 commits into
master
master
from
JY-20808-low-priority-indexing-queue
JY-20808-low-priority-indexing-queue
Copy head branch name to clipboard
Lines changed: 432 additions & 159 deletions
Conversation (5)
Conversation
(
5
)
Commits (36)
Commits
(
36
)
Checks (3)
Checks
(
3
)
Files changed (18)
Files changed
(
18
)
Pull Request Toolbar
Pull Request Toolbar
Collapse file tree
Open
JY-20808 low priority indexing queue
JY-20808 low priority indexing queue
#
12082
All commits
All commits
Vasil-Jiminny
Vasil-Jiminny
wants to merge 36 commits into
master
master
from
JY-20808-low-priority-indexing-queue
JY-20808-low-priority-indexing-queue
Copy head branch name to clipboard
0 of 18 files viewed
Awaiting approval
Awaiting approval
Submit review
Submit
review
Open diff view settings
Open overview panel
Open comments panel
(
0
)
Filter files…
Filter options
File tree
File tree
app
Component/ES
Listeners
UpdateMultipleTargetsListener.php
UpdateMultipleTargetsListener.php
UpdateSingleTargetListener.php
UpdateSingleTargetListener.php
Processor
Actions
UpsertDocumentsAction.php
UpsertDocumentsAction.php
DTOs...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira","depth":4,"bounds":{"left":0.0,"top":0.0518755,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.06304868,"width":0.10106383,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app","depth":4,"bounds":{"left":0.0,"top":0.08459697,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app","depth":5,"bounds":{"left":0.013297873,"top":0.09577015,"width":0.18816489,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app","depth":4,"bounds":{"left":0.0,"top":0.11731844,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app","depth":5,"bounds":{"left":0.013297873,"top":0.12849163,"width":0.15674867,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.06732048,"top":0.1245012,"width":0.007978723,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New Tab","depth":4,"bounds":{"left":0.0028257978,"top":0.15163608,"width":0.07413564,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"bounds":{"left":0.0028257978,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Close Google Gemini (⌃X)","depth":6,"bounds":{"left":0.013796543,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Tabs from other devices","depth":6,"bounds":{"left":0.024933511,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"bounds":{"left":0.036070477,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"bounds":{"left":0.04720745,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"AI Chat settings","depth":7,"bounds":{"left":0.35854387,"top":0.055067837,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Close","depth":7,"bounds":{"left":0.37051198,"top":0.055067837,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"WORK, Google Account: lukas.kovalik@jiminny.com","depth":12,"bounds":{"left":0.3678524,"top":0.103751,"width":0.013297873,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Main menu","depth":12,"bounds":{"left":0.08494016,"top":0.103751,"width":0.013297873,"height":0.031923383},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New chat","depth":12,"bounds":{"left":0.09823803,"top":0.10454908,"width":0.028590426,"height":0.030327214},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Gemini","depth":15,"bounds":{"left":0.1008976,"top":0.10973663,"width":0.021941489,"height":0.020351157},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"New Chat","depth":12,"bounds":{"left":0.33992687,"top":0.103751,"width":0.013297873,"height":0.031923383},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Open menu for conversation actions.","depth":12,"bounds":{"left":0.35322472,"top":0.103751,"width":0.013297873,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXHeading","text":"Conversation with Gemini","depth":15,"bounds":{"left":0.079288565,"top":0.14764565,"width":0.0003324468,"height":0.0007980846},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Conversation with Gemini","depth":16,"bounds":{"left":0.079288565,"top":0.15003991,"width":0.1200133,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Show the uploaded image in a lightbox","depth":21,"bounds":{"left":0.31848404,"top":0.01556265,"width":0.04288564,"height":0.2122905},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy prompt","depth":21,"bounds":{"left":0.17719415,"top":0.23743017,"width":0.013297873,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Edit","depth":21,"bounds":{"left":0.19182181,"top":0.23743017,"width":0.013297873,"height":0.031923383},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"You said Make a PR of changes Find potential issues and bottlenecks","depth":21,"bounds":{"left":0.21176861,"top":0.24381484,"width":0.14428191,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"You said","depth":23,"bounds":{"left":0.079288565,"top":0.24461293,"width":0.019946808,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Make a PR of changes Find potential issues and bottlenecks","depth":23,"bounds":{"left":0.21176861,"top":0.24541101,"width":0.14428191,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Listen","depth":22,"bounds":{"left":0.3480718,"top":0.29489225,"width":0.013297873,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Show thinking","depth":25,"bounds":{"left":0.12666224,"top":0.2972865,"width":0.030917553,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Gemini said","depth":20,"bounds":{"left":0.1243351,"top":0.3387869,"width":0.0003324468,"height":0.0007980846},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Gemini said","depth":21,"bounds":{"left":0.1243351,"top":0.34078214,"width":0.04105718,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"I can see you've uploaded a screenshot of a code diff, likely from a version control system given the red and green highlights. I would love to help you review the changes, spot bottlenecks, and help you draft a Pull Request.","depth":24,"bounds":{"left":0.11336436,"top":0.34277734,"width":0.24468085,"height":0.061053474},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"However,","depth":24,"bounds":{"left":0.11336436,"top":0.41859537,"width":0.0234375,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"the image resolution is far too low for me to read.","depth":24,"bounds":{"left":0.13680187,"top":0.41859537,"width":0.12732713,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"It appears to be a completely zoomed-out view where the code has been reduced to tiny, illegible pixels. Because of this, I cannot extract any text or logic to analyze.","depth":24,"bounds":{"left":0.11336436,"top":0.41859537,"width":0.2421875,"height":0.061053474},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"How You Can Share the Code","depth":23,"bounds":{"left":0.11336436,"top":0.5047885,"width":0.24534574,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"How You Can Share the Code","depth":24,"bounds":{"left":0.11336436,"top":0.5063847,"width":0.074634306,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"To help me review your code effectively, please try one of the following:","depth":24,"bounds":{"left":0.11336436,"top":0.53351957,"width":0.17237367,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Paste the text directly:","depth":26,"bounds":{"left":0.12599733,"top":0.5646449,"width":0.059175532,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Copy the specific code blocks (both the old and new versions if possible) and paste them directly into our chat.","depth":26,"bounds":{"left":0.12599733,"top":0.5646449,"width":0.21476063,"height":0.038707104},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Upload the files:","depth":26,"bounds":{"left":0.12599733,"top":0.6181165,"width":0.042220745,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"If the changes are extensive, you can upload the raw text or code files.","depth":26,"bounds":{"left":0.16821809,"top":0.6181165,"width":0.17154256,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Take high-resolution screenshots:","depth":26,"bounds":{"left":0.12599733,"top":0.6492418,"width":0.08843085,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"If you must use images, take closer, readable screenshots of the specific functions or methods you want me to review.","depth":26,"bounds":{"left":0.12599733,"top":0.6492418,"width":0.23021941,"height":0.038707104},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Once you provide the readable code, I can dive right in to identify potential bugs, assess performance bottlenecks, and help you summarize the changes for your PR!","depth":24,"bounds":{"left":0.11336436,"top":0.7067039,"width":0.24534574,"height":0.038707104},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Good response","depth":21,"bounds":{"left":0.1100399,"top":0.7633679,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Bad response","depth":21,"bounds":{"left":0.120678194,"top":0.7633679,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Redo","depth":21,"bounds":{"left":0.13131648,"top":0.7633679,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Share & export","depth":20,"bounds":{"left":0.1419548,"top":0.7633679,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy","depth":21,"bounds":{"left":0.15259309,"top":0.7633679,"width":0.010638298,"height":0.025538707},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Show more options","depth":20,"bounds":{"left":0.16323139,"top":0.7633679,"width":0.010638298,"height":0.025538707},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXTextArea","text":"Enter a prompt for Gemini\nencrypted","depth":20,"bounds":{"left":0.11469415,"top":0.83439744,"width":0.23670213,"height":0.01915403},"on_screen":true,"value":"Enter a prompt for Gemini\nencrypted","help_text":"","role_description":"text entry area","subrole":"AXUnknown","is_enabled":true,"is_focused":true,"is_selected":false},{"role":"AXStaticText","text":"Enter a prompt for Gemini","depth":21,"bounds":{"left":0.12134308,"top":0.8347965,"width":0.069980055,"height":0.018355945},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"encrypted","depth":21,"bounds":{"left":0.113696806,"top":0.83439744,"width":0.0066489363,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Open upload file menu","depth":20,"bounds":{"left":0.11070479,"top":0.87031126,"width":0.013297873,"height":0.031923383},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Tools","depth":18,"bounds":{"left":0.12666224,"top":0.87031126,"width":0.013297873,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Open mode picker","depth":20,"bounds":{"left":0.31399602,"top":0.867917,"width":0.026097074,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pro","depth":23,"bounds":{"left":0.31931517,"top":0.87669593,"width":0.007480053,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Microphone","depth":19,"bounds":{"left":0.34208778,"top":0.867917,"width":0.013297873,"height":0.031923383},"on_screen":true,"role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Send message","depth":19,"bounds":{"left":0.34840426,"top":0.8671189,"width":0.013962766,"height":0.033519555},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Your Jiminny chats aren’t used to improve our models. Gemini is AI. It can make mistakes, so double check it.","depth":17,"bounds":{"left":0.11303192,"top":0.92178774,"width":0.19996676,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Your privacy & Gemini Opens in a new window","depth":17,"bounds":{"left":0.31299868,"top":0.92178774,"width":0.040059842,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Your privacy & Gemini","depth":18,"bounds":{"left":0.31299868,"top":0.92178774,"width":0.040059842,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Opens in a new window","depth":19,"bounds":{"left":0.079288565,"top":0.92098963,"width":0.043218084,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Summarize page","depth":7,"bounds":{"left":0.08494016,"top":0.95730245,"width":0.053523935,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Summarize page","depth":9,"bounds":{"left":0.09059176,"top":0.96249,"width":0.042220745,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Skip to content","depth":6,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip to content","depth":7,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Open menu","depth":10,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Homepage (g then d)","depth":9,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"jiminny","depth":12,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"jiminny","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"app","depth":12,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"app","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Search or jump to…","depth":9,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Type","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"to search","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Chat with Copilot","depth":10,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXMenuButton","text":"Open Copilot…","depth":9,"on_screen":false,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXMenuButton","text":"Create new...","depth":9,"on_screen":false,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"All issues(g then i)","depth":9,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"All pull requests","depth":9,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"All repositories","depth":9,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"You have unread notifications(g then n)","depth":9,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Open user navigation menu","depth":9,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"Repository navigation","depth":9,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Repository navigation","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Code","depth":12,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Code","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Pull requests (31)","depth":12,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pull requests","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"31","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Agents","depth":12,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Agents","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Actions","depth":12,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Actions","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Wiki","depth":12,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Wiki","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Security and quality (1)","depth":12,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Security and quality","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Insights","depth":12,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Insights","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Settings","depth":12,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Settings","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Important update","depth":10,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Important update","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"On April 24 we'll start using GitHub Copilot interaction data for AI model training unless you opt out.","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review this update","depth":10,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review this update","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"and manage your preferences in your","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"GitHub account settings","depth":10,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"GitHub account settings","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":".","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Dismiss banner","depth":9,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"JY-20808 low priority indexing queue #12082 Edit title","depth":13,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"JY-20808 low priority indexing queue","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"12082","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Edit title","depth":14,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXMenuButton","text":"Preview","depth":13,"on_screen":false,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Preview","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Awaiting approval","depth":13,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Awaiting approval","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Code","depth":13,"on_screen":false,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Code","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Open","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Vasil-Jiminny","depth":15,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Vasil-Jiminny","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"wants to merge 36 commits into","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"master","depth":15,"on_screen":false,"role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"master","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"from","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"JY-20808-low-priority-indexing-queue","depth":16,"on_screen":false,"role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20808-low-priority-indexing-queue","depth":17,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy head branch name to clipboard","depth":16,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Lines changed: 432 additions & 159 deletions","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Conversation (5)","depth":16,"on_screen":false,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Conversation","depth":17,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"5","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Commits (36)","depth":16,"on_screen":false,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Commits","depth":17,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"36","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Checks (3)","depth":16,"on_screen":false,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Checks","depth":17,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Files changed (18)","depth":16,"on_screen":false,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"Files changed","depth":17,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"18","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Pull Request Toolbar","depth":14,"bounds":{"left":0.39993352,"top":0.075019956,"width":0.0003324468,"height":0.0007980846},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Pull Request Toolbar","depth":15,"bounds":{"left":0.39993352,"top":0.077813245,"width":0.030086435,"height":0.08060654},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Collapse file tree","depth":14,"bounds":{"left":0.39993352,"top":0.06424581,"width":0.00930851,"height":0.022346368},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXStaticText","text":"Open","depth":14,"bounds":{"left":0.4225399,"top":0.06863528,"width":0.011968086,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"JY-20808 low priority indexing queue","depth":14,"bounds":{"left":0.44115692,"top":0.057462092,"width":0.084773935,"height":0.016759777},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20808 low priority indexing queue","depth":16,"bounds":{"left":0.44115692,"top":0.05905826,"width":0.084773935,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#","depth":15,"bounds":{"left":0.52859044,"top":0.05905826,"width":0.0029920214,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"12082","depth":15,"bounds":{"left":0.5315825,"top":0.05905826,"width":0.013464096,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"All commits","depth":14,"bounds":{"left":0.43849733,"top":0.07102953,"width":0.03374335,"height":0.022346368},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"All commits","depth":16,"bounds":{"left":0.44148937,"top":0.07621708,"width":0.02244016,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Vasil-Jiminny","depth":15,"bounds":{"left":0.4765625,"top":0.075019956,"width":0.02642952,"height":0.014365523},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Vasil-Jiminny","depth":16,"bounds":{"left":0.4765625,"top":0.07621708,"width":0.02642952,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"wants to merge 36 commits into","depth":15,"bounds":{"left":0.5043218,"top":0.07621708,"width":0.06050532,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"master","depth":15,"bounds":{"left":0.5661569,"top":0.07342378,"width":0.018450798,"height":0.017557861},"on_screen":true,"role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"master","depth":16,"bounds":{"left":0.5681516,"top":0.07661612,"width":0.014461436,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"from","depth":16,"bounds":{"left":0.5859375,"top":0.07621708,"width":0.008643617,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"JY-20808-low-priority-indexing-queue","depth":16,"bounds":{"left":0.5959109,"top":0.07342378,"width":0.09042553,"height":0.017557861},"on_screen":true,"role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20808-low-priority-indexing-queue","depth":17,"bounds":{"left":0.5979056,"top":0.07661612,"width":0.08643617,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy head branch name to clipboard","depth":16,"bounds":{"left":0.68766624,"top":0.07102953,"width":0.00930851,"height":0.022346368},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"0 of 18 files viewed","depth":15,"bounds":{"left":0.81366354,"top":0.07661612,"width":0.01512633,"height":0.08060654},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Awaiting approval","depth":14,"bounds":{"left":0.85355717,"top":0.06424581,"width":0.04654255,"height":0.022346368},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Awaiting approval","depth":16,"bounds":{"left":0.86319816,"top":0.06943336,"width":0.033909574,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Submit review","depth":14,"bounds":{"left":0.9027593,"top":0.06424581,"width":0.03856383,"height":0.022346368},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Submit","depth":16,"bounds":{"left":0.90575135,"top":0.06943336,"width":0.014793883,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"review","depth":16,"bounds":{"left":0.9205452,"top":0.06943336,"width":0.012466756,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Open diff view settings","depth":14,"bounds":{"left":0.9439827,"top":0.071428575,"width":0.00930851,"height":0.022346368},"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Open overview panel","depth":14,"bounds":{"left":0.9616024,"top":0.071428575,"width":0.00930851,"height":0.022346368},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Open comments panel","depth":14,"bounds":{"left":0.9722407,"top":0.071428575,"width":0.017287234,"height":0.022346368},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"(","depth":16,"bounds":{"left":0.98055184,"top":0.07661612,"width":0.0026595744,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"0","depth":16,"bounds":{"left":0.98321146,"top":0.07661612,"width":0.0026595744,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")","depth":16,"bounds":{"left":0.985871,"top":0.07661612,"width":0.0014960107,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXTextField","text":"Filter files…","depth":16,"bounds":{"left":0.4112367,"top":0.12051077,"width":0.06815159,"height":0.023942538},"on_screen":true,"help_text":"","role_description":"text field","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXMenuButton","text":"Filter options","depth":16,"bounds":{"left":0.48238033,"top":0.11971269,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXHeading","text":"File tree","depth":15,"bounds":{"left":0.40026596,"top":0.15802075,"width":0.0003324468,"height":0.0007980846},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"File tree","depth":16,"bounds":{"left":0.40026596,"top":0.16081405,"width":0.014295213,"height":0.0518755},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app","depth":19,"bounds":{"left":0.4162234,"top":0.16400638,"width":0.008144947,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Component/ES","depth":21,"bounds":{"left":0.41888297,"top":0.18994413,"width":0.032081116,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Listeners","depth":23,"bounds":{"left":0.42154256,"top":0.21548285,"width":0.019614361,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"UpdateMultipleTargetsListener.php","depth":25,"bounds":{"left":0.4242021,"top":0.24102154,"width":0.07496676,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"UpdateMultipleTargetsListener.php","depth":26,"bounds":{"left":0.4242021,"top":0.24102154,"width":0.07496676,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"UpdateSingleTargetListener.php","depth":25,"bounds":{"left":0.4242021,"top":0.26656026,"width":0.06865027,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"UpdateSingleTargetListener.php","depth":26,"bounds":{"left":0.4242021,"top":0.26656026,"width":0.06865027,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Processor","depth":23,"bounds":{"left":0.42154256,"top":0.29209897,"width":0.021609042,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Actions","depth":25,"bounds":{"left":0.4242021,"top":0.3180367,"width":0.016123671,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"UpsertDocumentsAction.php","depth":27,"bounds":{"left":0.4268617,"top":0.34357542,"width":0.062333778,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"UpsertDocumentsAction.php","depth":28,"bounds":{"left":0.4268617,"top":0.35634476,"width":0.062333778,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"DTOs","depth":25,"bounds":{"left":0.4242021,"top":0.38188347,"width":0.011968086,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"}]...
|
-549294282644236879
|
-506013586208039506
|
idle
|
accessibility
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
Close tab
New Tab
Customize sidebar
Close Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
AI Chat settings
Close
WORK, Google Account: [EMAIL]
Main menu
New chat
Gemini
New Chat
Open menu for conversation actions.
Conversation with Gemini
Conversation with Gemini
Show the uploaded image in a lightbox
Copy prompt
Edit
You said Make a PR of changes Find potential issues and bottlenecks
You said
Make a PR of changes Find potential issues and bottlenecks
Listen
Show thinking
Gemini said
Gemini said
I can see you've uploaded a screenshot of a code diff, likely from a version control system given the red and green highlights. I would love to help you review the changes, spot bottlenecks, and help you draft a Pull Request.
However,
the image resolution is far too low for me to read.
It appears to be a completely zoomed-out view where the code has been reduced to tiny, illegible pixels. Because of this, I cannot extract any text or logic to analyze.
How You Can Share the Code
How You Can Share the Code
To help me review your code effectively, please try one of the following:
Paste the text directly:
Copy the specific code blocks (both the old and new versions if possible) and paste them directly into our chat.
Upload the files:
If the changes are extensive, you can upload the raw text or code files.
Take high-resolution screenshots:
If you must use images, take closer, readable screenshots of the specific functions or methods you want me to review.
Once you provide the readable code, I can dive right in to identify potential bugs, assess performance bottlenecks, and help you summarize the changes for your PR!
Good response
Bad response
Redo
Share & export
Copy
Show more options
Enter a prompt for Gemini
encrypted
Enter a prompt for Gemini
encrypted
Open upload file menu
Tools
Open mode picker
Pro
Microphone
Send message
Your Jiminny chats aren’t used to improve our models. Gemini is AI. It can make mistakes, so double check it.
Your privacy & Gemini Opens in a new window
Your privacy & Gemini
Opens in a new window
Summarize page
Summarize page
Skip to content
Skip to content
Open menu
Homepage (g then d)
jiminny
jiminny
app
app
Search or jump to…
Type
/
to search
Chat with Copilot
Open Copilot…
Create new...
All issues(g then i)
All pull requests
All repositories
You have unread notifications(g then n)
Open user navigation menu
Repository navigation
Repository navigation
Code
Code
Pull requests (31)
Pull requests
(
31
)
Agents
Agents
Actions
Actions
Wiki
Wiki
Security and quality (1)
Security and quality
(
1
)
Insights
Insights
Settings
Settings
Important update
Important update
On April 24 we'll start using GitHub Copilot interaction data for AI model training unless you opt out.
Review this update
Review this update
and manage your preferences in your
GitHub account settings
GitHub account settings
.
Dismiss banner
JY-20808 low priority indexing queue #12082 Edit title
JY-20808 low priority indexing queue
#
12082
Edit title
Preview
Preview
Awaiting approval
Awaiting approval
Code
Code
Open
Vasil-Jiminny
Vasil-Jiminny
wants to merge 36 commits into
master
master
from
JY-20808-low-priority-indexing-queue
JY-20808-low-priority-indexing-queue
Copy head branch name to clipboard
Lines changed: 432 additions & 159 deletions
Conversation (5)
Conversation
(
5
)
Commits (36)
Commits
(
36
)
Checks (3)
Checks
(
3
)
Files changed (18)
Files changed
(
18
)
Pull Request Toolbar
Pull Request Toolbar
Collapse file tree
Open
JY-20808 low priority indexing queue
JY-20808 low priority indexing queue
#
12082
All commits
All commits
Vasil-Jiminny
Vasil-Jiminny
wants to merge 36 commits into
master
master
from
JY-20808-low-priority-indexing-queue
JY-20808-low-priority-indexing-queue
Copy head branch name to clipboard
0 of 18 files viewed
Awaiting approval
Awaiting approval
Submit review
Submit
review
Open diff view settings
Open overview panel
Open comments panel
(
0
)
Filter files…
Filter options
File tree
File tree
app
Component/ES
Listeners
UpdateMultipleTargetsListener.php
UpdateMultipleTargetsListener.php
UpdateSingleTargetListener.php
UpdateSingleTargetListener.php
Processor
Actions
UpsertDocumentsAction.php
UpsertDocumentsAction.php
DTOs...
|
55679
|
NULL
|
NULL
|
NULL
|
|
55682
|
1933
|
12
|
2026-05-19T06:39:44.636480+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779172784636_m2.jpg...
|
Firefox
|
JY-20808 low priority indexing queue by Vasil-Jimi JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app — Work...
|
1
|
github.com/jiminny/app/pull/12082/changes#diff-49a github.com/jiminny/app/pull/12082/changes#diff-49a79d99c97caf7fc27ecb1dbacab5a29d871822caa0db0c71e94957c28c87af...
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
Close tab
New Tab
Customize sidebar
Close Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
AI Chat settings
Close
WORK, Google Account: [EMAIL]
Main menu
New chat
Gemini
New Chat
Open menu for conversation actions.
Conversation with Gemini
Conversation with Gemini
Show the uploaded image in a lightbox
Copy prompt
Edit
You said Make a PR of changes Find potential issues and bottlenecks
You said
Make a PR of changes Find potential issues and bottlenecks
Listen
Show thinking
Gemini said
Gemini said
I can see you've uploaded a screenshot of a code diff, likely from a version control system given the red and green highlights. I would love to help you review the changes, spot bottlenecks, and help you draft a Pull Request.
However,
the image resolution is far too low for me to read.
It appears to be a completely zoomed-out view where the code has been reduced to tiny, illegible pixels. Because of this, I cannot extract any text or logic to analyze.
How You Can Share the Code
How You Can Share the Code
To help me review your code effectively, please try one of the following:
Paste the text directly:
Copy the specific code blocks (both the old and new versions if possible) and paste them directly into our chat.
Upload the files:
If the changes are extensive, you can upload the raw text or code files.
Take high-resolution screenshots:
If you must use images, take closer, readable screenshots of the specific functions or methods you want me to review.
Once you provide the readable code, I can dive right in to identify potential bugs, assess performance bottlenecks, and help you summarize the changes for your PR!
Good response
Bad response
Redo
Share & export
Copy
Show more options
Enter a prompt for Gemini
encrypted
Enter a prompt for Gemini
encrypted
Open upload file menu
Tools
Open mode picker
Pro
Microphone
Send message
Your Jiminny chats aren’t used to improve our models. Gemini is AI. It can make mistakes, so double check it.
Your privacy & Gemini Opens in a new window
Your privacy & Gemini
Opens in a new window
Summarize page
Summarize page
Skip to content
Skip to content
Open menu
Homepage (g then d)
jiminny
jiminny
app
app
Search or jump to…
Type
/
to search
Chat with Copilot
Open Copilot…
Create new...
All issues(g then i)
All pull requests
All repositories
You have unread notifications(g then n)
Open user navigation menu
Repository navigation
Repository navigation
Code
Code
Pull requests (31)
Pull requests
(
31
)
Agents
Agents
Actions
Actions
Wiki
Wiki
Security and quality (1)
Security and quality
(
1
)
Insights
Insights
Settings
Settings
Important update
Important update
On April 24 we'll start using GitHub Copilot interaction data for AI model training unless you opt out.
Review this update
Review this update
and manage your preferences in your
GitHub account settings
GitHub account settings
.
Dismiss banner
JY-20808 low priority indexing queue #12082 Edit title
JY-20808 low priority indexing queue
#
12082
Edit title
Preview
Preview
Awaiting approval
Awaiting approval
Code
Code
Open
Vasil-Jiminny
Vasil-Jiminny
wants to merge 36 commits into
master
master
from
JY-20808-low-priority-indexing-queue
JY-20808-low-priority-indexing-queue
Copy head branch name to clipboard
Lines changed: 432 additions & 159 deletions
Conversation (5)
Conversation
(
5
)
Commits (36)
Commits
(
36
)
Checks (3)
Checks
(
3
)
Files changed (18)
Files changed
(
18
)
Pull Request Toolbar
Pull Request Toolbar
Collapse file tree
All commits
All commits
0 of 18 files viewed
Submit review
Submit
review
Open diff view settings
Open overview panel
Open comments panel
(
0
)
Filter files…
Filter options
File tree
File tree
app
Component/ES
Listeners
UpdateMultipleTargetsListener.php
UpdateMultipleTargetsListener.php
UpdateSingleTargetListener.php
UpdateSingleTargetListener.php
Processor
Actions
UpsertDocumentsAction.php
UpsertDocumentsAction.php
DTOs
SelectionList.php
SelectionList.php
Traits
SelectEntityListTrait.php
SelectEntityListTrait.php
TargetEntitiesSelector.php
TargetEntitiesSelector.php
AsyncUpdateElasticSearch.php
AsyncUpdateElasticSearch.php...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira","depth":4,"bounds":{"left":0.0,"top":0.0518755,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.06304868,"width":0.10106383,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app","depth":4,"bounds":{"left":0.0,"top":0.08459697,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app","depth":5,"bounds":{"left":0.013297873,"top":0.09577015,"width":0.18816489,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app","depth":4,"bounds":{"left":0.0,"top":0.11731844,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app","depth":5,"bounds":{"left":0.013297873,"top":0.12849163,"width":0.15674867,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.06732048,"top":0.1245012,"width":0.007978723,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New Tab","depth":4,"bounds":{"left":0.0028257978,"top":0.15163608,"width":0.07413564,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"bounds":{"left":0.0028257978,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Close Google Gemini (⌃X)","depth":6,"bounds":{"left":0.013796543,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Tabs from other devices","depth":6,"bounds":{"left":0.024933511,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"bounds":{"left":0.036070477,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"bounds":{"left":0.04720745,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"AI Chat settings","depth":7,"bounds":{"left":0.35854387,"top":0.055067837,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Close","depth":7,"bounds":{"left":0.37051198,"top":0.055067837,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"WORK, Google Account: lukas.kovalik@jiminny.com","depth":12,"bounds":{"left":0.3678524,"top":0.103751,"width":0.013297873,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Main menu","depth":12,"bounds":{"left":0.08494016,"top":0.103751,"width":0.013297873,"height":0.031923383},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New chat","depth":12,"bounds":{"left":0.09823803,"top":0.10454908,"width":0.028590426,"height":0.030327214},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Gemini","depth":15,"bounds":{"left":0.1008976,"top":0.10973663,"width":0.021941489,"height":0.020351157},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"New Chat","depth":12,"bounds":{"left":0.33992687,"top":0.103751,"width":0.013297873,"height":0.031923383},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Open menu for conversation actions.","depth":12,"bounds":{"left":0.35322472,"top":0.103751,"width":0.013297873,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXHeading","text":"Conversation with Gemini","depth":15,"bounds":{"left":0.079288565,"top":0.14764565,"width":0.0003324468,"height":0.0007980846},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Conversation with Gemini","depth":16,"bounds":{"left":0.079288565,"top":0.15003991,"width":0.1200133,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Show the uploaded image in a lightbox","depth":21,"bounds":{"left":0.31848404,"top":0.01556265,"width":0.04288564,"height":0.2122905},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy prompt","depth":21,"bounds":{"left":0.17719415,"top":0.23743017,"width":0.013297873,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Edit","depth":21,"bounds":{"left":0.19182181,"top":0.23743017,"width":0.013297873,"height":0.031923383},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"You said Make a PR of changes Find potential issues and bottlenecks","depth":21,"bounds":{"left":0.21176861,"top":0.24381484,"width":0.14428191,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"You said","depth":23,"bounds":{"left":0.079288565,"top":0.24461293,"width":0.019946808,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Make a PR of changes Find potential issues and bottlenecks","depth":23,"bounds":{"left":0.21176861,"top":0.24541101,"width":0.14428191,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Listen","depth":22,"bounds":{"left":0.3480718,"top":0.29489225,"width":0.013297873,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Show thinking","depth":25,"bounds":{"left":0.12666224,"top":0.2972865,"width":0.030917553,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Gemini said","depth":20,"bounds":{"left":0.1243351,"top":0.3387869,"width":0.0003324468,"height":0.0007980846},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Gemini said","depth":21,"bounds":{"left":0.1243351,"top":0.34078214,"width":0.04105718,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"I can see you've uploaded a screenshot of a code diff, likely from a version control system given the red and green highlights. I would love to help you review the changes, spot bottlenecks, and help you draft a Pull Request.","depth":24,"bounds":{"left":0.11336436,"top":0.34277734,"width":0.24468085,"height":0.061053474},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"However,","depth":24,"bounds":{"left":0.11336436,"top":0.41859537,"width":0.0234375,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"the image resolution is far too low for me to read.","depth":24,"bounds":{"left":0.13680187,"top":0.41859537,"width":0.12732713,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"It appears to be a completely zoomed-out view where the code has been reduced to tiny, illegible pixels. Because of this, I cannot extract any text or logic to analyze.","depth":24,"bounds":{"left":0.11336436,"top":0.41859537,"width":0.2421875,"height":0.061053474},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"How You Can Share the Code","depth":23,"bounds":{"left":0.11336436,"top":0.5047885,"width":0.24534574,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"How You Can Share the Code","depth":24,"bounds":{"left":0.11336436,"top":0.5063847,"width":0.074634306,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"To help me review your code effectively, please try one of the following:","depth":24,"bounds":{"left":0.11336436,"top":0.53351957,"width":0.17237367,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Paste the text directly:","depth":26,"bounds":{"left":0.12599733,"top":0.5646449,"width":0.059175532,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Copy the specific code blocks (both the old and new versions if possible) and paste them directly into our chat.","depth":26,"bounds":{"left":0.12599733,"top":0.5646449,"width":0.21476063,"height":0.038707104},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Upload the files:","depth":26,"bounds":{"left":0.12599733,"top":0.6181165,"width":0.042220745,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"If the changes are extensive, you can upload the raw text or code files.","depth":26,"bounds":{"left":0.16821809,"top":0.6181165,"width":0.17154256,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Take high-resolution screenshots:","depth":26,"bounds":{"left":0.12599733,"top":0.6492418,"width":0.08843085,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"If you must use images, take closer, readable screenshots of the specific functions or methods you want me to review.","depth":26,"bounds":{"left":0.12599733,"top":0.6492418,"width":0.23021941,"height":0.038707104},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Once you provide the readable code, I can dive right in to identify potential bugs, assess performance bottlenecks, and help you summarize the changes for your PR!","depth":24,"bounds":{"left":0.11336436,"top":0.7067039,"width":0.24534574,"height":0.038707104},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Good response","depth":21,"bounds":{"left":0.1100399,"top":0.7633679,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Bad response","depth":21,"bounds":{"left":0.120678194,"top":0.7633679,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Redo","depth":21,"bounds":{"left":0.13131648,"top":0.7633679,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Share & export","depth":20,"bounds":{"left":0.1419548,"top":0.7633679,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy","depth":21,"bounds":{"left":0.15259309,"top":0.7633679,"width":0.010638298,"height":0.025538707},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Show more options","depth":20,"bounds":{"left":0.16323139,"top":0.7633679,"width":0.010638298,"height":0.025538707},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXTextArea","text":"Enter a prompt for Gemini\nencrypted","depth":20,"bounds":{"left":0.11469415,"top":0.83439744,"width":0.23670213,"height":0.01915403},"on_screen":true,"value":"Enter a prompt for Gemini\nencrypted","help_text":"","role_description":"text entry area","subrole":"AXUnknown","is_enabled":true,"is_focused":true,"is_selected":false},{"role":"AXStaticText","text":"Enter a prompt for Gemini","depth":21,"bounds":{"left":0.12134308,"top":0.8347965,"width":0.069980055,"height":0.018355945},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"encrypted","depth":21,"bounds":{"left":0.113696806,"top":0.83439744,"width":0.0066489363,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Open upload file menu","depth":20,"bounds":{"left":0.11070479,"top":0.87031126,"width":0.013297873,"height":0.031923383},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Tools","depth":18,"bounds":{"left":0.12666224,"top":0.87031126,"width":0.013297873,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Open mode picker","depth":20,"bounds":{"left":0.31399602,"top":0.867917,"width":0.026097074,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pro","depth":23,"bounds":{"left":0.31931517,"top":0.87669593,"width":0.007480053,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Microphone","depth":19,"bounds":{"left":0.34208778,"top":0.867917,"width":0.013297873,"height":0.031923383},"on_screen":true,"role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Send message","depth":19,"bounds":{"left":0.34840426,"top":0.8671189,"width":0.013962766,"height":0.033519555},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Your Jiminny chats aren’t used to improve our models. Gemini is AI. It can make mistakes, so double check it.","depth":17,"bounds":{"left":0.11303192,"top":0.92178774,"width":0.19996676,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Your privacy & Gemini Opens in a new window","depth":17,"bounds":{"left":0.31299868,"top":0.92178774,"width":0.040059842,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Your privacy & Gemini","depth":18,"bounds":{"left":0.31299868,"top":0.92178774,"width":0.040059842,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Opens in a new window","depth":19,"bounds":{"left":0.079288565,"top":0.92098963,"width":0.043218084,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Summarize page","depth":7,"bounds":{"left":0.08494016,"top":0.95730245,"width":0.053523935,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Summarize page","depth":9,"bounds":{"left":0.09059176,"top":0.96249,"width":0.042220745,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Skip to content","depth":6,"bounds":{"left":0.38929522,"top":0.0518755,"width":0.0003324468,"height":0.0007980846},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip to content","depth":7,"bounds":{"left":0.38929522,"top":0.05347167,"width":0.0029920214,"height":0.21468475},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Open menu","depth":10,"bounds":{"left":0.39461437,"top":0.06464485,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Homepage (g then d)","depth":9,"bounds":{"left":0.40924203,"top":0.06464485,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"jiminny","depth":12,"bounds":{"left":0.4225399,"top":0.06464485,"width":0.018949468,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"jiminny","depth":14,"bounds":{"left":0.4245346,"top":0.07063048,"width":0.014960106,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"app","depth":12,"bounds":{"left":0.44647607,"top":0.06464485,"width":0.017785905,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"app","depth":14,"bounds":{"left":0.44847074,"top":0.07063048,"width":0.008477394,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Search or jump to…","depth":9,"bounds":{"left":0.8171542,"top":0.06464485,"width":0.06565824,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Type","depth":12,"bounds":{"left":0.8294548,"top":0.07063048,"width":0.011801862,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/","depth":12,"bounds":{"left":0.84258646,"top":0.07222666,"width":0.002493351,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"to search","depth":12,"bounds":{"left":0.8465758,"top":0.07063048,"width":0.021276595,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Chat with Copilot","depth":10,"bounds":{"left":0.88480717,"top":0.06464485,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXMenuButton","text":"Open Copilot…","depth":9,"bounds":{"left":0.89511305,"top":0.06464485,"width":0.008643617,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXMenuButton","text":"Create new...","depth":9,"bounds":{"left":0.91173536,"top":0.06464485,"width":0.01662234,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"All issues(g then i)","depth":9,"bounds":{"left":0.9310173,"top":0.06464485,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"All pull requests","depth":9,"bounds":{"left":0.94431514,"top":0.06464485,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"All repositories","depth":9,"bounds":{"left":0.95761305,"top":0.06464485,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"You have unread notifications(g then n)","depth":9,"bounds":{"left":0.9709109,"top":0.06464485,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Open user navigation menu","depth":9,"bounds":{"left":0.98420876,"top":0.06464485,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"Repository navigation","depth":9,"bounds":{"left":0.38896278,"top":0.051077414,"width":0.0003324468,"height":0.0007980846},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Repository navigation","depth":10,"bounds":{"left":0.38896278,"top":0.05387071,"width":0.0787899,"height":0.023144454},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Code","depth":12,"bounds":{"left":0.39461437,"top":0.09936153,"width":0.025099734,"height":0.026336791},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Code","depth":14,"bounds":{"left":0.40541887,"top":0.10574621,"width":0.011469414,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Pull requests (31)","depth":12,"bounds":{"left":0.42237368,"top":0.09936153,"width":0.054521278,"height":0.026336791},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pull requests","depth":14,"bounds":{"left":0.43301198,"top":0.10574621,"width":0.02925532,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":14,"bounds":{"left":0.46492687,"top":0.113727055,"width":0.0029920214,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"31","depth":14,"bounds":{"left":0.46791887,"top":0.113727055,"width":0.004986702,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")","depth":14,"bounds":{"left":0.47290558,"top":0.113727055,"width":0.0016622341,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Agents","depth":12,"bounds":{"left":0.47955453,"top":0.09936153,"width":0.029089095,"height":0.026336791},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Agents","depth":14,"bounds":{"left":0.49052528,"top":0.10574621,"width":0.014960106,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Actions","depth":12,"bounds":{"left":0.5113032,"top":0.09936153,"width":0.03025266,"height":0.026336791},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Actions","depth":14,"bounds":{"left":0.52244014,"top":0.10574621,"width":0.015957447,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Wiki","depth":12,"bounds":{"left":0.54421544,"top":0.09936153,"width":0.022938829,"height":0.026336791},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Wiki","depth":14,"bounds":{"left":0.55502,"top":0.10574621,"width":0.009142287,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Security and quality (1)","depth":12,"bounds":{"left":0.56981385,"top":0.09936153,"width":0.0674867,"height":0.026336791},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Security and quality","depth":14,"bounds":{"left":0.5816157,"top":0.10574621,"width":0.04255319,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":14,"bounds":{"left":0.62799203,"top":0.113727055,"width":0.0029920214,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1","depth":14,"bounds":{"left":0.63098407,"top":0.113727055,"width":0.0019946808,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")","depth":14,"bounds":{"left":0.63297874,"top":0.113727055,"width":0.0018284575,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Insights","depth":12,"bounds":{"left":0.6399601,"top":0.09936153,"width":0.031083776,"height":0.026336791},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Insights","depth":14,"bounds":{"left":0.65109706,"top":0.10574621,"width":0.016788565,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Settings","depth":12,"bounds":{"left":0.67370343,"top":0.09936153,"width":0.032081116,"height":0.026336791},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Settings","depth":14,"bounds":{"left":0.68484044,"top":0.10574621,"width":0.017785905,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Important update","depth":10,"bounds":{"left":0.40292552,"top":0.14365523,"width":0.0003324468,"height":0.016759777},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Important update","depth":11,"bounds":{"left":0.40292552,"top":0.1452514,"width":0.039228722,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"On April 24 we'll start using GitHub Copilot interaction data for AI model training unless you opt out.","depth":10,"bounds":{"left":0.40292552,"top":0.1452514,"width":0.2159242,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review this update","depth":10,"bounds":{"left":0.61884975,"top":0.1452514,"width":0.04055851,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review this update","depth":11,"bounds":{"left":0.61884975,"top":0.1452514,"width":0.04055851,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"and manage your preferences in your","depth":10,"bounds":{"left":0.6594083,"top":0.1452514,"width":0.08261303,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"GitHub account settings","depth":10,"bounds":{"left":0.74202126,"top":0.1452514,"width":0.05219415,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"GitHub account settings","depth":11,"bounds":{"left":0.74202126,"top":0.1452514,"width":0.05219415,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":".","depth":10,"bounds":{"left":0.79421544,"top":0.1452514,"width":0.0013297872,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Dismiss banner","depth":9,"bounds":{"left":0.9865359,"top":0.13886672,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"JY-20808 low priority indexing queue #12082 Edit title","depth":13,"bounds":{"left":0.39993352,"top":0.19193934,"width":0.22307181,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"JY-20808 low priority indexing queue","depth":14,"bounds":{"left":0.39993352,"top":0.19273743,"width":0.17204122,"height":0.030327214},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#","depth":15,"bounds":{"left":0.5746343,"top":0.19273743,"width":0.0066489363,"height":0.030327214},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"12082","depth":15,"bounds":{"left":0.5812833,"top":0.19273743,"width":0.029753989,"height":0.030327214},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Edit title","depth":14,"bounds":{"left":0.61236703,"top":0.19513169,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXMenuButton","text":"Preview","depth":13,"bounds":{"left":0.9584442,"top":0.19992019,"width":0.031083776,"height":0.022346368},"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Preview","depth":15,"bounds":{"left":0.9637633,"top":0.2047087,"width":0.01512633,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Awaiting approval","depth":13,"bounds":{"left":0.86818486,"top":0.19832402,"width":0.055352394,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Awaiting approval","depth":15,"bounds":{"left":0.88048536,"top":0.20430966,"width":0.03873005,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Code","depth":13,"bounds":{"left":0.9261968,"top":0.19832402,"width":0.02825798,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Code","depth":15,"bounds":{"left":0.9305186,"top":0.20430966,"width":0.011635638,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Open","depth":13,"bounds":{"left":0.4105718,"top":0.23623304,"width":0.011968086,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Vasil-Jiminny","depth":15,"bounds":{"left":0.42918882,"top":0.2330407,"width":0.03025266,"height":0.016759777},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Vasil-Jiminny","depth":16,"bounds":{"left":0.42918882,"top":0.23463687,"width":0.03025266,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"wants to merge 36 commits into","depth":15,"bounds":{"left":0.46077126,"top":0.23463687,"width":0.06931516,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"master","depth":15,"bounds":{"left":0.53141624,"top":0.23264167,"width":0.018450798,"height":0.017557861},"on_screen":true,"role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"master","depth":16,"bounds":{"left":0.5334109,"top":0.235834,"width":0.014461436,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"from","depth":16,"bounds":{"left":0.5511968,"top":0.23463687,"width":0.009973404,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"JY-20808-low-priority-indexing-queue","depth":16,"bounds":{"left":0.5625,"top":0.23264167,"width":0.090259306,"height":0.017557861},"on_screen":true,"role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20808-low-priority-indexing-queue","depth":17,"bounds":{"left":0.56449467,"top":0.235834,"width":0.086269945,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy head branch name to clipboard","depth":16,"bounds":{"left":0.6540891,"top":0.23024741,"width":0.00930851,"height":0.022346368},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Lines changed: 432 additions & 159 deletions","depth":14,"bounds":{"left":0.9522939,"top":0.28651237,"width":0.019946808,"height":0.11412609},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Conversation (5)","depth":16,"bounds":{"left":0.39993352,"top":0.26855546,"width":0.0546875,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Conversation","depth":17,"bounds":{"left":0.41223404,"top":0.27813247,"width":0.02825798,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":18,"bounds":{"left":0.4502992,"top":0.27813247,"width":0.0029920214,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"5","depth":18,"bounds":{"left":0.45329124,"top":0.27813247,"width":0.0028257978,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")","depth":18,"bounds":{"left":0.45611703,"top":0.27813247,"width":0.0018284575,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Commits (36)","depth":16,"bounds":{"left":0.45462102,"top":0.26855546,"width":0.04837101,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Commits","depth":17,"bounds":{"left":0.46692154,"top":0.27813247,"width":0.019115692,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":18,"bounds":{"left":0.49867022,"top":0.27813247,"width":0.0029920214,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"36","depth":18,"bounds":{"left":0.50166225,"top":0.27813247,"width":0.005817819,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")","depth":18,"bounds":{"left":0.50748,"top":0.27813247,"width":0.0016622341,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Checks (3)","depth":16,"bounds":{"left":0.50299203,"top":0.26855546,"width":0.042386968,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Checks","depth":17,"bounds":{"left":0.5152925,"top":0.27813247,"width":0.015957447,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":18,"bounds":{"left":0.54105717,"top":0.27813247,"width":0.0029920214,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3","depth":18,"bounds":{"left":0.5440492,"top":0.27813247,"width":0.0028257978,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")","depth":18,"bounds":{"left":0.546875,"top":0.27813247,"width":0.0018284575,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Files changed (18)","depth":16,"bounds":{"left":0.545379,"top":0.26855546,"width":0.058344416,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"Files changed","depth":17,"bounds":{"left":0.55767953,"top":0.27813247,"width":0.029753989,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":18,"bounds":{"left":0.5994016,"top":0.27813247,"width":0.0029920214,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"18","depth":18,"bounds":{"left":0.6023936,"top":0.27813247,"width":0.0051529254,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")","depth":18,"bounds":{"left":0.60754657,"top":0.27813247,"width":0.0016622341,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Pull Request Toolbar","depth":14,"bounds":{"left":0.39993352,"top":0.3236233,"width":0.0003324468,"height":0.0007980846},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Pull Request Toolbar","depth":15,"bounds":{"left":0.39993352,"top":0.3264166,"width":0.030086435,"height":0.08060654},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Collapse file tree","depth":14,"bounds":{"left":0.39993352,"top":0.31284916,"width":0.00930851,"height":0.022346368},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXButton","text":"All commits","depth":14,"bounds":{"left":0.4119016,"top":0.31284916,"width":0.040392287,"height":0.022346368},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"All commits","depth":16,"bounds":{"left":0.42154256,"top":0.3180367,"width":0.02244016,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"0 of 18 files viewed","depth":15,"bounds":{"left":0.8630319,"top":0.32521948,"width":0.014960106,"height":0.08060654},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Submit review","depth":14,"bounds":{"left":0.9027593,"top":0.31284916,"width":0.03856383,"height":0.022346368},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Submit","depth":16,"bounds":{"left":0.90575135,"top":0.3180367,"width":0.014793883,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"review","depth":16,"bounds":{"left":0.9205452,"top":0.3180367,"width":0.012466756,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Open diff view settings","depth":14,"bounds":{"left":0.9439827,"top":0.31284916,"width":0.00930851,"height":0.022346368},"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Open overview panel","depth":14,"bounds":{"left":0.9616024,"top":0.31284916,"width":0.00930851,"height":0.022346368},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Open comments panel","depth":14,"bounds":{"left":0.9722407,"top":0.31284916,"width":0.017287234,"height":0.022346368},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"(","depth":16,"bounds":{"left":0.98055184,"top":0.3180367,"width":0.0026595744,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"0","depth":16,"bounds":{"left":0.98321146,"top":0.3180367,"width":0.0026595744,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")","depth":16,"bounds":{"left":0.985871,"top":0.3180367,"width":0.0014960107,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXTextField","text":"Filter files…","depth":16,"bounds":{"left":0.4112367,"top":0.36193135,"width":0.06815159,"height":0.023942538},"on_screen":true,"help_text":"","role_description":"text field","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXMenuButton","text":"Filter options","depth":16,"bounds":{"left":0.48238033,"top":0.36113328,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXHeading","text":"File tree","depth":15,"bounds":{"left":0.40026596,"top":0.39944133,"width":0.0003324468,"height":0.0007980846},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"File tree","depth":16,"bounds":{"left":0.40026596,"top":0.40223464,"width":0.014295213,"height":0.0518755},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app","depth":19,"bounds":{"left":0.4162234,"top":0.40542698,"width":0.008144947,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Component/ES","depth":21,"bounds":{"left":0.41888297,"top":0.43136472,"width":0.032081116,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Listeners","depth":23,"bounds":{"left":0.42154256,"top":0.45690343,"width":0.019614361,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"UpdateMultipleTargetsListener.php","depth":25,"bounds":{"left":0.4242021,"top":0.48244214,"width":0.07496676,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"UpdateMultipleTargetsListener.php","depth":26,"bounds":{"left":0.4242021,"top":0.48244214,"width":0.07496676,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"UpdateSingleTargetListener.php","depth":25,"bounds":{"left":0.4242021,"top":0.5079808,"width":0.06865027,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"UpdateSingleTargetListener.php","depth":26,"bounds":{"left":0.4242021,"top":0.5079808,"width":0.06865027,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Processor","depth":23,"bounds":{"left":0.42154256,"top":0.53351957,"width":0.021609042,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Actions","depth":25,"bounds":{"left":0.4242021,"top":0.5594573,"width":0.016123671,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"UpsertDocumentsAction.php","depth":27,"bounds":{"left":0.4268617,"top":0.584996,"width":0.062333778,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"UpsertDocumentsAction.php","depth":28,"bounds":{"left":0.4268617,"top":0.584996,"width":0.062333778,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"DTOs","depth":25,"bounds":{"left":0.4242021,"top":0.6105347,"width":0.011968086,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SelectionList.php","depth":27,"bounds":{"left":0.4268617,"top":0.63647246,"width":0.03723404,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"SelectionList.php","depth":28,"bounds":{"left":0.4268617,"top":0.63647246,"width":0.03723404,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Traits","depth":25,"bounds":{"left":0.4242021,"top":0.66201115,"width":0.011968086,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SelectEntityListTrait.php","depth":27,"bounds":{"left":0.4268617,"top":0.6875499,"width":0.05236037,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"SelectEntityListTrait.php","depth":28,"bounds":{"left":0.4268617,"top":0.6875499,"width":0.05236037,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"TargetEntitiesSelector.php","depth":25,"bounds":{"left":0.4242021,"top":0.7130886,"width":0.05668218,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"TargetEntitiesSelector.php","depth":26,"bounds":{"left":0.4242021,"top":0.7130886,"width":0.05668218,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"AsyncUpdateElasticSearch.php","depth":23,"bounds":{"left":0.42154256,"top":0.7386273,"width":0.06732048,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"AsyncUpdateElasticSearch.php","depth":24,"bounds":{"left":0.42154256,"top":0.7386273,"width":0.06732048,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"}]...
|
-8132900048441828791
|
-506567740064244241
|
visual_change
|
accessibility
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
Close tab
New Tab
Customize sidebar
Close Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
AI Chat settings
Close
WORK, Google Account: [EMAIL]
Main menu
New chat
Gemini
New Chat
Open menu for conversation actions.
Conversation with Gemini
Conversation with Gemini
Show the uploaded image in a lightbox
Copy prompt
Edit
You said Make a PR of changes Find potential issues and bottlenecks
You said
Make a PR of changes Find potential issues and bottlenecks
Listen
Show thinking
Gemini said
Gemini said
I can see you've uploaded a screenshot of a code diff, likely from a version control system given the red and green highlights. I would love to help you review the changes, spot bottlenecks, and help you draft a Pull Request.
However,
the image resolution is far too low for me to read.
It appears to be a completely zoomed-out view where the code has been reduced to tiny, illegible pixels. Because of this, I cannot extract any text or logic to analyze.
How You Can Share the Code
How You Can Share the Code
To help me review your code effectively, please try one of the following:
Paste the text directly:
Copy the specific code blocks (both the old and new versions if possible) and paste them directly into our chat.
Upload the files:
If the changes are extensive, you can upload the raw text or code files.
Take high-resolution screenshots:
If you must use images, take closer, readable screenshots of the specific functions or methods you want me to review.
Once you provide the readable code, I can dive right in to identify potential bugs, assess performance bottlenecks, and help you summarize the changes for your PR!
Good response
Bad response
Redo
Share & export
Copy
Show more options
Enter a prompt for Gemini
encrypted
Enter a prompt for Gemini
encrypted
Open upload file menu
Tools
Open mode picker
Pro
Microphone
Send message
Your Jiminny chats aren’t used to improve our models. Gemini is AI. It can make mistakes, so double check it.
Your privacy & Gemini Opens in a new window
Your privacy & Gemini
Opens in a new window
Summarize page
Summarize page
Skip to content
Skip to content
Open menu
Homepage (g then d)
jiminny
jiminny
app
app
Search or jump to…
Type
/
to search
Chat with Copilot
Open Copilot…
Create new...
All issues(g then i)
All pull requests
All repositories
You have unread notifications(g then n)
Open user navigation menu
Repository navigation
Repository navigation
Code
Code
Pull requests (31)
Pull requests
(
31
)
Agents
Agents
Actions
Actions
Wiki
Wiki
Security and quality (1)
Security and quality
(
1
)
Insights
Insights
Settings
Settings
Important update
Important update
On April 24 we'll start using GitHub Copilot interaction data for AI model training unless you opt out.
Review this update
Review this update
and manage your preferences in your
GitHub account settings
GitHub account settings
.
Dismiss banner
JY-20808 low priority indexing queue #12082 Edit title
JY-20808 low priority indexing queue
#
12082
Edit title
Preview
Preview
Awaiting approval
Awaiting approval
Code
Code
Open
Vasil-Jiminny
Vasil-Jiminny
wants to merge 36 commits into
master
master
from
JY-20808-low-priority-indexing-queue
JY-20808-low-priority-indexing-queue
Copy head branch name to clipboard
Lines changed: 432 additions & 159 deletions
Conversation (5)
Conversation
(
5
)
Commits (36)
Commits
(
36
)
Checks (3)
Checks
(
3
)
Files changed (18)
Files changed
(
18
)
Pull Request Toolbar
Pull Request Toolbar
Collapse file tree
All commits
All commits
0 of 18 files viewed
Submit review
Submit
review
Open diff view settings
Open overview panel
Open comments panel
(
0
)
Filter files…
Filter options
File tree
File tree
app
Component/ES
Listeners
UpdateMultipleTargetsListener.php
UpdateMultipleTargetsListener.php
UpdateSingleTargetListener.php
UpdateSingleTargetListener.php
Processor
Actions
UpsertDocumentsAction.php
UpsertDocumentsAction.php
DTOs
SelectionList.php
SelectionList.php
Traits
SelectEntityListTrait.php
SelectEntityListTrait.php
TargetEntitiesSelector.php
TargetEntitiesSelector.php
AsyncUpdateElasticSearch.php
AsyncUpdateElasticSearch.php...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
55683
|
1932
|
9
|
2026-05-19T06:39:46.176304+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779172786176_m1.jpg...
|
Firefox
|
JY-20808 low priority indexing queue by Vasil-Jimi JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app — Work...
|
1
|
github.com/jiminny/app/pull/12082/changes#diff-49a github.com/jiminny/app/pull/12082/changes#diff-49a79d99c97caf7fc27ecb1dbacab5a29d871822caa0db0c71e94957c28c87af...
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
Close tab
New Tab
Customize sidebar
Close Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
AI Chat settings
Close
WORK, Google Account: [EMAIL]
Main menu
New chat
Gemini
New Chat
Open menu for conversation actions.
Conversation with Gemini
Conversation with Gemini
Show the uploaded image in a lightbox
Copy prompt
Edit
You said Make a PR of changes Find potential issues and bottlenecks
You said
Make a PR of changes Find potential issues and bottlenecks
Listen
Show thinking
Gemini said
Gemini said
I can see you've uploaded a screenshot of a code diff, likely from a version control system given the red and green highlights. I would love to help you review the changes, spot bottlenecks, and help you draft a Pull Request.
However,
the image resolution is far too low for me to read.
It appears to be a completely zoomed-out view where the code has been reduced to tiny, illegible pixels. Because of this, I cannot extract any text or logic to analyze.
How You Can Share the Code
How You Can Share the Code
To help me review your code effectively, please try one of the following:
Paste the text directly:
Copy the specific code blocks (both the old and new versions if possible) and paste them directly into our chat.
Upload the files:
If the changes are extensive, you can upload the raw text or code files.
Take high-resolution screenshots:
If you must use images, take closer, readable screenshots of the specific functions or methods you want me to review.
Once you provide the readable code, I can dive right in to identify potential bugs, assess performance bottlenecks, and help you summarize the changes for your PR!
Good response
Bad response
Redo
Share & export
Copy
Show more options
Enter a prompt for Gemini
encrypted
Enter a prompt for Gemini
encrypted
Open upload file menu
Tools
Open mode picker
Pro
Microphone
Send message
Your Jiminny chats aren’t used to improve our models. Gemini is AI. It can make mistakes, so double check it.
Your privacy & Gemini Opens in a new window
Your privacy & Gemini
Opens in a new window
Summarize page
Summarize page
Skip to content
Skip to content
Open menu
Homepage (g then d)
jiminny
jiminny
app
app
Search or jump to…
Type
/
to search
Chat with Copilot
Open Copilot…
Create new...
All issues(g then i)
All pull requests
All repositories
You have unread notifications(g then n)
Open user navigation menu
Repository navigation
Repository navigation
Code
Code
Pull requests (31)
Pull requests
(
31
)
Agents
Agents
Actions
Actions
Wiki
Wiki
Security and quality (1)
Security and quality
(
1
)
Insights
Insights
Settings
Settings
Important update
Important update
On April 24 we'll start using GitHub Copilot interaction data for AI model training unless you opt out.
Review this update
Review this update
and manage your preferences in your
GitHub account settings
GitHub account settings
.
Dismiss banner
JY-20808 low priority indexing queue #12082 Edit title
JY-20808 low priority indexing queue
#...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New Tab","depth":4,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Close Google Gemini (⌃X)","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Tabs from other devices","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"AI Chat settings","depth":7,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Close","depth":7,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"WORK, Google Account: lukas.kovalik@jiminny.com","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Main menu","depth":12,"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New chat","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Gemini","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"New Chat","depth":12,"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Open menu for conversation actions.","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXHeading","text":"Conversation with Gemini","depth":15,"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Conversation with Gemini","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Show the uploaded image in a lightbox","depth":21,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy prompt","depth":21,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Edit","depth":21,"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"You said Make a PR of changes Find potential issues and bottlenecks","depth":21,"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"You said","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Make a PR of changes Find potential issues and bottlenecks","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Listen","depth":22,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Show thinking","depth":25,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Gemini said","depth":20,"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Gemini said","depth":21,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"I can see you've uploaded a screenshot of a code diff, likely from a version control system given the red and green highlights. I would love to help you review the changes, spot bottlenecks, and help you draft a Pull Request.","depth":24,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"However,","depth":24,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"the image resolution is far too low for me to read.","depth":24,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"It appears to be a completely zoomed-out view where the code has been reduced to tiny, illegible pixels. Because of this, I cannot extract any text or logic to analyze.","depth":24,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"How You Can Share the Code","depth":23,"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"How You Can Share the Code","depth":24,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"To help me review your code effectively, please try one of the following:","depth":24,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Paste the text directly:","depth":26,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Copy the specific code blocks (both the old and new versions if possible) and paste them directly into our chat.","depth":26,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Upload the files:","depth":26,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"If the changes are extensive, you can upload the raw text or code files.","depth":26,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Take high-resolution screenshots:","depth":26,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"If you must use images, take closer, readable screenshots of the specific functions or methods you want me to review.","depth":26,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Once you provide the readable code, I can dive right in to identify potential bugs, assess performance bottlenecks, and help you summarize the changes for your PR!","depth":24,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Good response","depth":21,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Bad response","depth":21,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Redo","depth":21,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Share & export","depth":20,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy","depth":21,"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Show more options","depth":20,"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXTextArea","text":"Enter a prompt for Gemini\nencrypted","depth":20,"on_screen":true,"value":"Enter a prompt for Gemini\nencrypted","help_text":"","role_description":"text entry area","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Enter a prompt for Gemini","depth":21,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"encrypted","depth":21,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Open upload file menu","depth":20,"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Tools","depth":18,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Open mode picker","depth":20,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pro","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Microphone","depth":19,"on_screen":true,"role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Send message","depth":19,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Your Jiminny chats aren’t used to improve our models. Gemini is AI. It can make mistakes, so double check it.","depth":17,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Your privacy & Gemini Opens in a new window","depth":17,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Your privacy & Gemini","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Opens in a new window","depth":19,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Summarize page","depth":7,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Summarize page","depth":9,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Skip to content","depth":6,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip to content","depth":7,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Open menu","depth":10,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Homepage (g then d)","depth":9,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"jiminny","depth":12,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"jiminny","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"app","depth":12,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"app","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Search or jump to…","depth":9,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Type","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"to search","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Chat with Copilot","depth":10,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXMenuButton","text":"Open Copilot…","depth":9,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXMenuButton","text":"Create new...","depth":9,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"All issues(g then i)","depth":9,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"All pull requests","depth":9,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"All repositories","depth":9,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"You have unread notifications(g then n)","depth":9,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Open user navigation menu","depth":9,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"Repository navigation","depth":9,"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Repository navigation","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Code","depth":12,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Code","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Pull requests (31)","depth":12,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pull requests","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"31","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Agents","depth":12,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Agents","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Actions","depth":12,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Actions","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Wiki","depth":12,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Wiki","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Security and quality (1)","depth":12,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Security and quality","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Insights","depth":12,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Insights","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Settings","depth":12,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Settings","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Important update","depth":10,"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Important update","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"On April 24 we'll start using GitHub Copilot interaction data for AI model training unless you opt out.","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review this update","depth":10,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review this update","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"and manage your preferences in your","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"GitHub account settings","depth":10,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"GitHub account settings","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":".","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Dismiss banner","depth":9,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"JY-20808 low priority indexing queue #12082 Edit title","depth":13,"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"JY-20808 low priority indexing queue","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"}]...
|
8796582150660617861
|
-506567737916629363
|
click
|
accessibility
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
Close tab
New Tab
Customize sidebar
Close Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
AI Chat settings
Close
WORK, Google Account: [EMAIL]
Main menu
New chat
Gemini
New Chat
Open menu for conversation actions.
Conversation with Gemini
Conversation with Gemini
Show the uploaded image in a lightbox
Copy prompt
Edit
You said Make a PR of changes Find potential issues and bottlenecks
You said
Make a PR of changes Find potential issues and bottlenecks
Listen
Show thinking
Gemini said
Gemini said
I can see you've uploaded a screenshot of a code diff, likely from a version control system given the red and green highlights. I would love to help you review the changes, spot bottlenecks, and help you draft a Pull Request.
However,
the image resolution is far too low for me to read.
It appears to be a completely zoomed-out view where the code has been reduced to tiny, illegible pixels. Because of this, I cannot extract any text or logic to analyze.
How You Can Share the Code
How You Can Share the Code
To help me review your code effectively, please try one of the following:
Paste the text directly:
Copy the specific code blocks (both the old and new versions if possible) and paste them directly into our chat.
Upload the files:
If the changes are extensive, you can upload the raw text or code files.
Take high-resolution screenshots:
If you must use images, take closer, readable screenshots of the specific functions or methods you want me to review.
Once you provide the readable code, I can dive right in to identify potential bugs, assess performance bottlenecks, and help you summarize the changes for your PR!
Good response
Bad response
Redo
Share & export
Copy
Show more options
Enter a prompt for Gemini
encrypted
Enter a prompt for Gemini
encrypted
Open upload file menu
Tools
Open mode picker
Pro
Microphone
Send message
Your Jiminny chats aren’t used to improve our models. Gemini is AI. It can make mistakes, so double check it.
Your privacy & Gemini Opens in a new window
Your privacy & Gemini
Opens in a new window
Summarize page
Summarize page
Skip to content
Skip to content
Open menu
Homepage (g then d)
jiminny
jiminny
app
app
Search or jump to…
Type
/
to search
Chat with Copilot
Open Copilot…
Create new...
All issues(g then i)
All pull requests
All repositories
You have unread notifications(g then n)
Open user navigation menu
Repository navigation
Repository navigation
Code
Code
Pull requests (31)
Pull requests
(
31
)
Agents
Agents
Actions
Actions
Wiki
Wiki
Security and quality (1)
Security and quality
(
1
)
Insights
Insights
Settings
Settings
Important update
Important update
On April 24 we'll start using GitHub Copilot interaction data for AI model training unless you opt out.
Review this update
Review this update
and manage your preferences in your
GitHub account settings
GitHub account settings
.
Dismiss banner
JY-20808 low priority indexing queue #12082 Edit title
JY-20808 low priority indexing queue
#...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
55684
|
1932
|
10
|
2026-05-19T06:40:01.845113+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779172801845_m1.jpg...
|
Firefox
|
JY-20808 low priority indexing queue by Vasil-Jimi JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app — Work...
|
1
|
github.com/jiminny/app/pull/12082/changes#diff-49a github.com/jiminny/app/pull/12082/changes#diff-49a79d99c97caf7fc27ecb1dbacab5a29d871822caa0db0c71e94957c28c87af...
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
Close tab
New Tab
Customize sidebar
Close Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
AI Chat settings
Close
WORK, Google Account: [EMAIL]
Main menu
New chat
Gemini
New Chat
Open menu for conversation actions.
Conversation with Gemini
Conversation with Gemini
Show the uploaded image in a lightbox
Copy prompt
Edit
You said Make a PR of changes Find potential issues and bottlenecks
You said
Make a PR of changes Find potential issues and bottlenecks
Listen
Show thinking
Gemini said
Gemini said
I can see you've uploaded a screenshot of a code diff, likely from a version control system given the red and green highlights. I would love to help you review the changes, spot bottlenecks, and help you draft a Pull Request.
However,
the image resolution is far too low for me to read.
It appears to be a completely zoomed-out view where the code has been reduced to tiny, illegible pixels. Because of this, I cannot extract any text or logic to analyze.
How You Can Share the Code
How You Can Share the Code
To help me review your code effectively, please try one of the following:
Paste the text directly:
Copy the specific code blocks (both the old and new versions if possible) and paste them directly into our chat.
Upload the files:
If the changes are extensive, you can upload the raw text or code files.
Take high-resolution screenshots:
If you must use images, take closer, readable screenshots of the specific functions or methods you want me to review.
Once you provide the readable code, I can dive right in to identify potential bugs, assess performance bottlenecks, and help you summarize the changes for your PR!
Good response
Bad response
Redo
Share & export
Copy
Show more options
Enter a prompt for Gemini
encrypted
Enter a prompt for Gemini
encrypted
Open upload file menu
Tools
Open mode picker
Pro
Microphone
Send message
Your Jiminny chats aren’t used to improve our models. Gemini is AI. It can make mistakes, so double check it.
Your privacy & Gemini Opens in a new window
Your privacy & Gemini
Opens in a new window
Summarize page
Summarize page
Skip to content
Skip to content
Open menu
Homepage (g then d)
jiminny
jiminny
app
app
Search or jump to…
Type
/
to search
Chat with Copilot
Open Copilot…
Create new...
All issues(g then i)
All pull requests
All repositories
You have unread notifications(g then n)
Open user navigation menu
Repository navigation
Repository navigation
Code
Code
Pull requests (31)
Pull requests
(
31
)
Agents
Agents
Actions
Actions
Wiki
Wiki
Security and quality (1)
Security and quality
(
1
)
Insights
Insights
Settings
Settings
Important update
Important update
On April 24 we'll start using GitHub Copilot interaction data for AI model training unless you opt out.
Review this update
Review this update
and manage your preferences in your
GitHub account settings
GitHub account settings
.
Dismiss banner
JY-20808 low priority indexing queue #12082 Edit title
JY-20808 low priority indexing queue
#
12082
Edit title
Preview
Preview
Awaiting approval
Awaiting approval
Code
Code
Open
Vasil-Jiminny
Vasil-Jiminny
wants to merge 36 commits into
master
master
from
JY-20808-low-priority-indexing-queue
JY-20808-low-priority-indexing-queue
Copy head branch name to clipboard
Lines changed: 432 additions & 159 deletions
Conversation (5)
Conversation
(
5
)
Commits (36)
Commits
(
36
)
Checks (3)
Checks
(
3
)
Files changed (18)
Files changed
(
18
)
Pull Request Toolbar
Pull Request Toolbar
Collapse file tree
Open
JY-20808 low priority indexing queue
JY-20808 low priority indexing queue
#
12082
All commits
All commits
Vasil-Jiminny
Vasil-Jiminny
wants to merge 36 commits into
master
master
from
JY-20808-low-priority-indexing-queue
JY-20808-low-priority-indexing-queue
Copy head branch name to clipboard
0 of 18 files viewed
Awaiting approval
Awaiting approval
Submit review
Submit
review
Open diff view settings
Open overview panel
Open comments panel...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New Tab","depth":4,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Close Google Gemini (⌃X)","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Tabs from other devices","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"AI Chat settings","depth":7,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Close","depth":7,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"WORK, Google Account: lukas.kovalik@jiminny.com","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Main menu","depth":12,"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New chat","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Gemini","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"New Chat","depth":12,"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Open menu for conversation actions.","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXHeading","text":"Conversation with Gemini","depth":15,"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Conversation with Gemini","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Show the uploaded image in a lightbox","depth":21,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy prompt","depth":21,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Edit","depth":21,"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"You said Make a PR of changes Find potential issues and bottlenecks","depth":21,"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"You said","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Make a PR of changes Find potential issues and bottlenecks","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Listen","depth":22,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Show thinking","depth":25,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Gemini said","depth":20,"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Gemini said","depth":21,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"I can see you've uploaded a screenshot of a code diff, likely from a version control system given the red and green highlights. I would love to help you review the changes, spot bottlenecks, and help you draft a Pull Request.","depth":24,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"However,","depth":24,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"the image resolution is far too low for me to read.","depth":24,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"It appears to be a completely zoomed-out view where the code has been reduced to tiny, illegible pixels. Because of this, I cannot extract any text or logic to analyze.","depth":24,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"How You Can Share the Code","depth":23,"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"How You Can Share the Code","depth":24,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"To help me review your code effectively, please try one of the following:","depth":24,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Paste the text directly:","depth":26,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Copy the specific code blocks (both the old and new versions if possible) and paste them directly into our chat.","depth":26,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Upload the files:","depth":26,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"If the changes are extensive, you can upload the raw text or code files.","depth":26,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Take high-resolution screenshots:","depth":26,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"If you must use images, take closer, readable screenshots of the specific functions or methods you want me to review.","depth":26,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Once you provide the readable code, I can dive right in to identify potential bugs, assess performance bottlenecks, and help you summarize the changes for your PR!","depth":24,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Good response","depth":21,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Bad response","depth":21,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Redo","depth":21,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Share & export","depth":20,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy","depth":21,"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Show more options","depth":20,"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXTextArea","text":"Enter a prompt for Gemini\nencrypted","depth":20,"on_screen":true,"value":"Enter a prompt for Gemini\nencrypted","help_text":"","role_description":"text entry area","subrole":"AXUnknown","is_enabled":true,"is_focused":true,"is_selected":false},{"role":"AXStaticText","text":"Enter a prompt for Gemini","depth":21,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"encrypted","depth":21,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Open upload file menu","depth":20,"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Tools","depth":18,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Open mode picker","depth":20,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pro","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Microphone","depth":19,"on_screen":true,"role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Send message","depth":19,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Your Jiminny chats aren’t used to improve our models. Gemini is AI. It can make mistakes, so double check it.","depth":17,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Your privacy & Gemini Opens in a new window","depth":17,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Your privacy & Gemini","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Opens in a new window","depth":19,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Summarize page","depth":7,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Summarize page","depth":9,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Skip to content","depth":6,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip to content","depth":7,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Open menu","depth":10,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Homepage (g then d)","depth":9,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"jiminny","depth":12,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"jiminny","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"app","depth":12,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"app","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Search or jump to…","depth":9,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Type","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"to search","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Chat with Copilot","depth":10,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXMenuButton","text":"Open Copilot…","depth":9,"on_screen":false,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXMenuButton","text":"Create new...","depth":9,"on_screen":false,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"All issues(g then i)","depth":9,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"All pull requests","depth":9,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"All repositories","depth":9,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"You have unread notifications(g then n)","depth":9,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Open user navigation menu","depth":9,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"Repository navigation","depth":9,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Repository navigation","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Code","depth":12,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Code","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Pull requests (31)","depth":12,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pull requests","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"31","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Agents","depth":12,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Agents","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Actions","depth":12,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Actions","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Wiki","depth":12,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Wiki","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Security and quality (1)","depth":12,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Security and quality","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Insights","depth":12,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Insights","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Settings","depth":12,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Settings","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Important update","depth":10,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Important update","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"On April 24 we'll start using GitHub Copilot interaction data for AI model training unless you opt out.","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review this update","depth":10,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review this update","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"and manage your preferences in your","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"GitHub account settings","depth":10,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"GitHub account settings","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":".","depth":10,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Dismiss banner","depth":9,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"JY-20808 low priority indexing queue #12082 Edit title","depth":13,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"JY-20808 low priority indexing queue","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"12082","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Edit title","depth":14,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXMenuButton","text":"Preview","depth":13,"on_screen":false,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Preview","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Awaiting approval","depth":13,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Awaiting approval","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Code","depth":13,"on_screen":false,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Code","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Open","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Vasil-Jiminny","depth":15,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Vasil-Jiminny","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"wants to merge 36 commits into","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"master","depth":15,"on_screen":false,"role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"master","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"from","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"JY-20808-low-priority-indexing-queue","depth":16,"on_screen":false,"role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20808-low-priority-indexing-queue","depth":17,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy head branch name to clipboard","depth":16,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Lines changed: 432 additions & 159 deletions","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Conversation (5)","depth":16,"on_screen":false,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Conversation","depth":17,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"5","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Commits (36)","depth":16,"on_screen":false,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Commits","depth":17,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"36","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Checks (3)","depth":16,"on_screen":false,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Checks","depth":17,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Files changed (18)","depth":16,"on_screen":false,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"Files changed","depth":17,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"18","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Pull Request Toolbar","depth":14,"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Pull Request Toolbar","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Collapse file tree","depth":14,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXStaticText","text":"Open","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"JY-20808 low priority indexing queue","depth":14,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20808 low priority indexing queue","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"12082","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"All commits","depth":14,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"All commits","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Vasil-Jiminny","depth":15,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Vasil-Jiminny","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"wants to merge 36 commits into","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"master","depth":15,"on_screen":true,"role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"master","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"from","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"JY-20808-low-priority-indexing-queue","depth":16,"on_screen":true,"role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20808-low-priority-indexing-queue","depth":17,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy head branch name to clipboard","depth":16,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"0 of 18 files viewed","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Awaiting approval","depth":14,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Awaiting approval","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Submit review","depth":14,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Submit","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"review","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Open diff view settings","depth":14,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Open overview panel","depth":14,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Open comments panel","depth":14,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-9130636576713593948
|
-506083952800539442
|
click
|
accessibility
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
Close tab
New Tab
Customize sidebar
Close Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
AI Chat settings
Close
WORK, Google Account: [EMAIL]
Main menu
New chat
Gemini
New Chat
Open menu for conversation actions.
Conversation with Gemini
Conversation with Gemini
Show the uploaded image in a lightbox
Copy prompt
Edit
You said Make a PR of changes Find potential issues and bottlenecks
You said
Make a PR of changes Find potential issues and bottlenecks
Listen
Show thinking
Gemini said
Gemini said
I can see you've uploaded a screenshot of a code diff, likely from a version control system given the red and green highlights. I would love to help you review the changes, spot bottlenecks, and help you draft a Pull Request.
However,
the image resolution is far too low for me to read.
It appears to be a completely zoomed-out view where the code has been reduced to tiny, illegible pixels. Because of this, I cannot extract any text or logic to analyze.
How You Can Share the Code
How You Can Share the Code
To help me review your code effectively, please try one of the following:
Paste the text directly:
Copy the specific code blocks (both the old and new versions if possible) and paste them directly into our chat.
Upload the files:
If the changes are extensive, you can upload the raw text or code files.
Take high-resolution screenshots:
If you must use images, take closer, readable screenshots of the specific functions or methods you want me to review.
Once you provide the readable code, I can dive right in to identify potential bugs, assess performance bottlenecks, and help you summarize the changes for your PR!
Good response
Bad response
Redo
Share & export
Copy
Show more options
Enter a prompt for Gemini
encrypted
Enter a prompt for Gemini
encrypted
Open upload file menu
Tools
Open mode picker
Pro
Microphone
Send message
Your Jiminny chats aren’t used to improve our models. Gemini is AI. It can make mistakes, so double check it.
Your privacy & Gemini Opens in a new window
Your privacy & Gemini
Opens in a new window
Summarize page
Summarize page
Skip to content
Skip to content
Open menu
Homepage (g then d)
jiminny
jiminny
app
app
Search or jump to…
Type
/
to search
Chat with Copilot
Open Copilot…
Create new...
All issues(g then i)
All pull requests
All repositories
You have unread notifications(g then n)
Open user navigation menu
Repository navigation
Repository navigation
Code
Code
Pull requests (31)
Pull requests
(
31
)
Agents
Agents
Actions
Actions
Wiki
Wiki
Security and quality (1)
Security and quality
(
1
)
Insights
Insights
Settings
Settings
Important update
Important update
On April 24 we'll start using GitHub Copilot interaction data for AI model training unless you opt out.
Review this update
Review this update
and manage your preferences in your
GitHub account settings
GitHub account settings
.
Dismiss banner
JY-20808 low priority indexing queue #12082 Edit title
JY-20808 low priority indexing queue
#
12082
Edit title
Preview
Preview
Awaiting approval
Awaiting approval
Code
Code
Open
Vasil-Jiminny
Vasil-Jiminny
wants to merge 36 commits into
master
master
from
JY-20808-low-priority-indexing-queue
JY-20808-low-priority-indexing-queue
Copy head branch name to clipboard
Lines changed: 432 additions & 159 deletions
Conversation (5)
Conversation
(
5
)
Commits (36)
Commits
(
36
)
Checks (3)
Checks
(
3
)
Files changed (18)
Files changed
(
18
)
Pull Request Toolbar
Pull Request Toolbar
Collapse file tree
Open
JY-20808 low priority indexing queue
JY-20808 low priority indexing queue
#
12082
All commits
All commits
Vasil-Jiminny
Vasil-Jiminny
wants to merge 36 commits into
master
master
from
JY-20808-low-priority-indexing-queue
JY-20808-low-priority-indexing-queue
Copy head branch name to clipboard
0 of 18 files viewed
Awaiting approval
Awaiting approval
Submit review
Submit
review
Open diff view settings
Open overview panel
Open comments panel...
|
55683
|
NULL
|
NULL
|
NULL
|
|
55685
|
1933
|
13
|
2026-05-19T06:40:15.016302+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779172815016_m2.jpg...
|
Firefox
|
NULL
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
slackcalVIewHomeActivityFilesLateMoreJiminny ...# slackcalVIewHomeActivityFilesLateMoreJiminny ...# conrusion-clinic# curiosity lab# engineering# general#jiminny-bg# platform-tickets# product launchesic random# releases# sofia-office# support# thank-yousit the peovle of iimi...^? Direct messageswVasil VasileyGalya DimitrovaAneliva AngelovaP. Nikolay Yankov2 Stefka StovanovaStoyan Tomovsa Todor Stamatov MMario GeorgievNikolay Ivanova James GrahamStoyan Tanev#a Stelivan GeorgievMistonWindowHelp@ Describe what you are looking for# engineering8 24MessagesCanvase FilesMoreFriday. May 15thYesterdayllan Kvuchukoy 4:26 PM@here please don't denloy in the next 15mins, we need a release to go through fonJllan Kvuchukov 5-7 PMDeblovs are onen again.Circlec APP 9-31 AM• 1. PR with vu nerability hxes is readv forreviewPlease take a look at the code and conhrmthat evervthing works pronerly on vourlocal machine or on a planet environmentiPull requests (iminny aoo)•#12097 hx/securitv: nom denendencvuodates - 2026-05-19 (secfix/nom-20260519)1Vew workilow runMessage #engineering+ Aal5a20d871822caa0dh0r71e01057/28c87afomponent/ES/Listeners/eMultiple largetsListener.phpes changed: ¿ adcitions ‹ celetion87 OpenJY-20808 low orioritv indexing queue #12082|Vasil-Jiminny wants to merge 36 commits into master from JY-20808-low-priority-indexing-queue• Filter files.....v • app• — Component/ES|v = Listeners* UpdateMultipleTargetsListen..# UpdateSingleTargetListener..• { Processorv ActionsE UpsertDocumentsAction.phpv / DTOs* SelectionList.php• ^ Traits• SelectEntitvListTrait.ohp* TargetEntitiesSelector.phpE1 AsvncUpdateElasticSearch.ohp# QueuePriorityEnum.ohp* UpdateProcessManager.phpv ^ Console/Commands/Elasticsear….+ AsvnclIndateFsFntities.nhn₴ ResetAsyncElasticSearchCom..> Ea tests/Unit/Component/ES|app/Console/Commands/Elasticsearch/ResetAsyncElasticSearchCommand.php Luse Jiminny component ES Processor Traits Val1dateUodatelargettra1t:use Jamanny ycomponentics rrocessorupadtelarget,use Jiminny\Component\ES\Repositories\EsResetRepositoryInterface;use Jiminny\Exceptions\Inval1dArgumentException;use Jiminny\Traits\GracefullyStoppable;Ca -144,7 +145,10 @a private function shouldResetElasticSearchInternals(): void144private function getRemainingScheduledEntities(bool SprintStatus = false): intSremainingReqular = AsyncUpdateElasticSearch::getEntitiesListcount(Sthis->updateTarget);SremainingPriority = AsvncUpdateElasticSearch::getEntitiesListCount(Sthis->updateTarget, true);148if (SprintStatus) <Sthis->line(v tests/Unit/Component/ES/Processor/DTOs/SelectionListTest.php +@а -5.84 +5.140 %dnamespace Tests\Unit\Component\ES\Processor\DT0s;use Jiminny\Component\ES\Processor\DT0s\SelectionList;use PHPUnit\Framework\Attributes\CoversClass;use PHPUnit Framework TestCase:#[CoversClass(SelectionList::class)]|final class Selectionl ictTect eytends TectCasepublic function testGetEntityIds(): void• Enter a prompt for GeminiPro vYour Jiminny chats aren't used to improve our models. Gemini is Al. It can make mistakes, so double check it. Your privacy & GeminiSummarize page"Dally - Platrorm• in om100% C7. • Tue 19 May 9:40:14• 0 18 viewed• Awaiting approval+5 -1 0000Vieweduse J1minnv componentES Processor Traits ValidateUodatelargettrait:use Jiminny\Component\ES\Processor\UpdateTarget;12 + use Jiminny\Component\ES\QueuePriorityEnum;use Jiminny\Component\ES\Repositories\EsResetRepositoryInterface;146148149150152o uuse Jimanny\Exceptions\Inval1dArgumentException;use Jiminny\Traits\GracefullyStoppable;private function getRemainingScheduledEntities(bool SprintStatus = talse): 1ntSremainingReqular = AsyncUpdateElasticSearch::qetEntitiesListcount(Sthis->updateTarget);SremaininaPriority = AsvncUpdateElasticSearch::aetEntitiesListcountlSthis->updateTaraet.QueuePriorityEnum: :HIGHif (SprintStatus) {Sthis-sline(+103 -47 aaae Viewednamesnace Testslllnit\Connonent\FS\Processor\DT0c•use Jiminny\Component\ES\Processor\DT0s\SelectionList;+ use Jiminny ComponentES QueuePriorityEnum:use PHPUnit\Framework\Attributes\CoversClass;use PHPUnit\Framework\TestCase:#CoversClass(SelectionList::class)]|final clacs Selectionl istTect extends TectCasenrivate conct int CHINK ST7F = 109•publie function testAdEntAEyLIStAnGetAL LI8St): Vos$selectionList = new SelectionList();SselectionList->addEntitvList(OueuePrioritvEnum::HIGH. [1. 21):SselectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);Sthis->assertSame([1, 2, 3, 4], $selectionList->getAllIds());...
|
NULL
|
232278514891996878
|
NULL
|
visual_change
|
ocr
|
NULL
|
slackcalVIewHomeActivityFilesLateMoreJiminny ...# slackcalVIewHomeActivityFilesLateMoreJiminny ...# conrusion-clinic# curiosity lab# engineering# general#jiminny-bg# platform-tickets# product launchesic random# releases# sofia-office# support# thank-yousit the peovle of iimi...^? Direct messageswVasil VasileyGalya DimitrovaAneliva AngelovaP. Nikolay Yankov2 Stefka StovanovaStoyan Tomovsa Todor Stamatov MMario GeorgievNikolay Ivanova James GrahamStoyan Tanev#a Stelivan GeorgievMistonWindowHelp@ Describe what you are looking for# engineering8 24MessagesCanvase FilesMoreFriday. May 15thYesterdayllan Kvuchukoy 4:26 PM@here please don't denloy in the next 15mins, we need a release to go through fonJllan Kvuchukov 5-7 PMDeblovs are onen again.Circlec APP 9-31 AM• 1. PR with vu nerability hxes is readv forreviewPlease take a look at the code and conhrmthat evervthing works pronerly on vourlocal machine or on a planet environmentiPull requests (iminny aoo)•#12097 hx/securitv: nom denendencvuodates - 2026-05-19 (secfix/nom-20260519)1Vew workilow runMessage #engineering+ Aal5a20d871822caa0dh0r71e01057/28c87afomponent/ES/Listeners/eMultiple largetsListener.phpes changed: ¿ adcitions ‹ celetion87 OpenJY-20808 low orioritv indexing queue #12082|Vasil-Jiminny wants to merge 36 commits into master from JY-20808-low-priority-indexing-queue• Filter files.....v • app• — Component/ES|v = Listeners* UpdateMultipleTargetsListen..# UpdateSingleTargetListener..• { Processorv ActionsE UpsertDocumentsAction.phpv / DTOs* SelectionList.php• ^ Traits• SelectEntitvListTrait.ohp* TargetEntitiesSelector.phpE1 AsvncUpdateElasticSearch.ohp# QueuePriorityEnum.ohp* UpdateProcessManager.phpv ^ Console/Commands/Elasticsear….+ AsvnclIndateFsFntities.nhn₴ ResetAsyncElasticSearchCom..> Ea tests/Unit/Component/ES|app/Console/Commands/Elasticsearch/ResetAsyncElasticSearchCommand.php Luse Jiminny component ES Processor Traits Val1dateUodatelargettra1t:use Jamanny ycomponentics rrocessorupadtelarget,use Jiminny\Component\ES\Repositories\EsResetRepositoryInterface;use Jiminny\Exceptions\Inval1dArgumentException;use Jiminny\Traits\GracefullyStoppable;Ca -144,7 +145,10 @a private function shouldResetElasticSearchInternals(): void144private function getRemainingScheduledEntities(bool SprintStatus = false): intSremainingReqular = AsyncUpdateElasticSearch::getEntitiesListcount(Sthis->updateTarget);SremainingPriority = AsvncUpdateElasticSearch::getEntitiesListCount(Sthis->updateTarget, true);148if (SprintStatus) <Sthis->line(v tests/Unit/Component/ES/Processor/DTOs/SelectionListTest.php +@а -5.84 +5.140 %dnamespace Tests\Unit\Component\ES\Processor\DT0s;use Jiminny\Component\ES\Processor\DT0s\SelectionList;use PHPUnit\Framework\Attributes\CoversClass;use PHPUnit Framework TestCase:#[CoversClass(SelectionList::class)]|final class Selectionl ictTect eytends TectCasepublic function testGetEntityIds(): void• Enter a prompt for GeminiPro vYour Jiminny chats aren't used to improve our models. Gemini is Al. It can make mistakes, so double check it. Your privacy & GeminiSummarize page"Dally - Platrorm• in om100% C7. • Tue 19 May 9:40:14• 0 18 viewed• Awaiting approval+5 -1 0000Vieweduse J1minnv componentES Processor Traits ValidateUodatelargettrait:use Jiminny\Component\ES\Processor\UpdateTarget;12 + use Jiminny\Component\ES\QueuePriorityEnum;use Jiminny\Component\ES\Repositories\EsResetRepositoryInterface;146148149150152o uuse Jimanny\Exceptions\Inval1dArgumentException;use Jiminny\Traits\GracefullyStoppable;private function getRemainingScheduledEntities(bool SprintStatus = talse): 1ntSremainingReqular = AsyncUpdateElasticSearch::qetEntitiesListcount(Sthis->updateTarget);SremaininaPriority = AsvncUpdateElasticSearch::aetEntitiesListcountlSthis->updateTaraet.QueuePriorityEnum: :HIGHif (SprintStatus) {Sthis-sline(+103 -47 aaae Viewednamesnace Testslllnit\Connonent\FS\Processor\DT0c•use Jiminny\Component\ES\Processor\DT0s\SelectionList;+ use Jiminny ComponentES QueuePriorityEnum:use PHPUnit\Framework\Attributes\CoversClass;use PHPUnit\Framework\TestCase:#CoversClass(SelectionList::class)]|final clacs Selectionl istTect extends TectCasenrivate conct int CHINK ST7F = 109•publie function testAdEntAEyLIStAnGetAL LI8St): Vos$selectionList = new SelectionList();SselectionList->addEntitvList(OueuePrioritvEnum::HIGH. [1. 21):SselectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);Sthis->assertSame([1, 2, 3, 4], $selectionList->getAllIds());...
|
55682
|
NULL
|
NULL
|
NULL
|
|
55686
|
1933
|
14
|
2026-05-19T06:40:17.262516+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779172817262_m2.jpg...
|
Firefox
|
NULL
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
slackcalVIewHomeActivityFilesLateMoreJiminny ...# slackcalVIewHomeActivityFilesLateMoreJiminny ...# conrusion-clinic# curiosity lab# engineering# general#jiminny-bg# platform-tickets# product launchesic random# releases# sofia-office# support# thank-yousit the peovle of iimi...^? Direct messageswVasil VasileyGalya DimitrovaAneliva AngelovaP. Nikolay Yankov2 Stefka StovanovaStoyan Tomovsa Todor Stamatov MMario GeorgievNikolay Ivanova James GrahamStoyan Tanev#a Stelivan GeorgievMistonWindowHelp@ Describe what you are looking for# engineering8 24MessagesCanvase FilesMoreFriday. May 15thYesterday ~llan Kvuchukoy 4:26 PM@here please don't denloy in the next 15mins, we need a release to go through fonJllan Kvuchukov 5-7 PMDeblovs are onen again.Circlec APP 9-31 AM• 1. PR with vu nerability hxes is readv forreviewPlease take a look at the code and conhrmthat evervthing works pronerly on vourlocal machine or on a planet environmentiPull requests (iminny aoo)•#12097 hx/securitv: nom denendencvuodates - 2026-05-19 (secfix/nom-20260519)1Vew workilow runMessage #engineering+ Aal5a20d871822caa0dh0r71e01057/28c87afomponent/ES/Listeners/eMultiple largetsListener.phpes changed: ¿ adcitions ‹ celetion87 OpenJY-20808 low orioritv indexing queue #12082|Vasil-Jiminny wants to merge 36 commits into master from JY-20808-low-priority-indexing-queue• Filter files.....v • app• — Component/ES|v = Listeners* UpdateMultipleTargetsListen..# UpdateSingleTargetListener..• { Processorv ActionsE UpsertDocumentsAction.phpv / DTOs* SelectionList.php• ^ Traits# SelectEntitvListTrait.ohp* TargetEntitiesSelector.phpE1 AsvncUpdateElasticSearch.ohp# QueuePriorityEnum.ohn* UpdateProcessManager.phpv ^ Console/Commands/Elasticsear….+ AsvnclIndateFsFntities.nhn₴ ResetAsyncElasticSearchCom..> Ea tests/Unit/Component/ES|app/Console/Commands/Elasticsearch/ResetAsyncElasticSearchCommand.php L*use Jiminny component ES Processor Traits Val1dateUodatelargettra1t:use Jamanny ycomponentics rrocessorupadtelarget,use Jiminny\Component\ES\Repositories\EsResetRepositoryInterface;use Jiminny\Exceptions\Inval1dArgumentException;use Jiminny\Traits\GracefullyStoppable;Ca -144,7 +145,10 @a private function shouldResetElasticSearchInternals(): void144private tunction getRemainingScheduledEntities(bool SprintStatus = talse): intSremainingReqular = AsyncUpdateElasticSearch::getEntitiesListcountSthis->updateTarget);SremainingPriority = AsvncUpdateElasticSearch::getEntitiesListCount(Sthis->updateTarget, true);148if (SprintStatus)<Sthis->line(v tests/Unit/Component/ES/Processor/DTOs/SelectionListTest.php +@а -5.84 +5.140 %dnamespace Tests\Unit\Component\ES\Processor\DT0s;use Jiminny\Component\ES\Processor\DT0s\SelectionList;use PHPUnit\Framework\Attributes\CoversClass;use PHPUnit Framework TestCase:#[CoversClass(SelectionList::class)]|final class Selectionl ictTect eytends TectCasepublic function testGetEntityIds(): void• Enter a prompt for GeminiProvYour Jiminny chats aren't used to improve our models. Gemini is Al. It can make mistakes, so double check it. Your privacy & GeminiSummarize page"Dally - Platrorm• in om100% C7 • Tue 19 May 9:40:16• 0 18 viewed• Awaiting approval+5 -1 0000Vieweduse J1minnv componentES Processor Traits ValidateUodatelargettra1t:use Jiminny\Component\ES\Processor\UpdateTarget;12 + use Jiminny\Component\ES\QueuePriorityEnum;use Jiminny\Component\ES\Repositories\EsResetRepositoryInterface;146148149150152use Jimanny\Exceptions\Inval1dArgumentException;use Jiminny\Traits\GracefullyStoppable;private function getRemainingScheduledEntities(bool SprintStatus = talse): 1ntSremainingReqular = AsyncUpdateElasticSearch::qetEntitiesListcount(Sthis->updateTarget);SremaininaPriority = AsvncUpdateElasticSearch::qetEntitiesListcountlSthis->updateTaraet.QueuePriorityEnum: :HIGHif (SprintStatus) {Sthis-sline(+103 -47 aaae Viewednamesnace Testslllnit\Connonent\FS\Processor\DT0c•use Jiminny\Component\ES\Processor\DT0s\SelectionList;+ use Jiminny ComponentES QueuePriorityEnum:use PHPUnit\Framework\Attributes\CoversClass;use PHPUnit\Framework\TestCase:#CoversClass(SelectionList::class)]|final clacs Selectionl istTect extends TectCasenrivate conct int CHINK ST7F = 109•publie function testAdEntAEyLIStAnGetAL LI8St): Vos$selectionList = new SelectionList();SselectionList->addEntitvList(OueuePrioritvEnum::HIGH. [1. 21):SselectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);Sthis->assertSame([1, 2, 3, 4], $selectionList->getAllIds());...
|
NULL
|
-5505935951241521811
|
NULL
|
click
|
ocr
|
NULL
|
slackcalVIewHomeActivityFilesLateMoreJiminny ...# slackcalVIewHomeActivityFilesLateMoreJiminny ...# conrusion-clinic# curiosity lab# engineering# general#jiminny-bg# platform-tickets# product launchesic random# releases# sofia-office# support# thank-yousit the peovle of iimi...^? Direct messageswVasil VasileyGalya DimitrovaAneliva AngelovaP. Nikolay Yankov2 Stefka StovanovaStoyan Tomovsa Todor Stamatov MMario GeorgievNikolay Ivanova James GrahamStoyan Tanev#a Stelivan GeorgievMistonWindowHelp@ Describe what you are looking for# engineering8 24MessagesCanvase FilesMoreFriday. May 15thYesterday ~llan Kvuchukoy 4:26 PM@here please don't denloy in the next 15mins, we need a release to go through fonJllan Kvuchukov 5-7 PMDeblovs are onen again.Circlec APP 9-31 AM• 1. PR with vu nerability hxes is readv forreviewPlease take a look at the code and conhrmthat evervthing works pronerly on vourlocal machine or on a planet environmentiPull requests (iminny aoo)•#12097 hx/securitv: nom denendencvuodates - 2026-05-19 (secfix/nom-20260519)1Vew workilow runMessage #engineering+ Aal5a20d871822caa0dh0r71e01057/28c87afomponent/ES/Listeners/eMultiple largetsListener.phpes changed: ¿ adcitions ‹ celetion87 OpenJY-20808 low orioritv indexing queue #12082|Vasil-Jiminny wants to merge 36 commits into master from JY-20808-low-priority-indexing-queue• Filter files.....v • app• — Component/ES|v = Listeners* UpdateMultipleTargetsListen..# UpdateSingleTargetListener..• { Processorv ActionsE UpsertDocumentsAction.phpv / DTOs* SelectionList.php• ^ Traits# SelectEntitvListTrait.ohp* TargetEntitiesSelector.phpE1 AsvncUpdateElasticSearch.ohp# QueuePriorityEnum.ohn* UpdateProcessManager.phpv ^ Console/Commands/Elasticsear….+ AsvnclIndateFsFntities.nhn₴ ResetAsyncElasticSearchCom..> Ea tests/Unit/Component/ES|app/Console/Commands/Elasticsearch/ResetAsyncElasticSearchCommand.php L*use Jiminny component ES Processor Traits Val1dateUodatelargettra1t:use Jamanny ycomponentics rrocessorupadtelarget,use Jiminny\Component\ES\Repositories\EsResetRepositoryInterface;use Jiminny\Exceptions\Inval1dArgumentException;use Jiminny\Traits\GracefullyStoppable;Ca -144,7 +145,10 @a private function shouldResetElasticSearchInternals(): void144private tunction getRemainingScheduledEntities(bool SprintStatus = talse): intSremainingReqular = AsyncUpdateElasticSearch::getEntitiesListcountSthis->updateTarget);SremainingPriority = AsvncUpdateElasticSearch::getEntitiesListCount(Sthis->updateTarget, true);148if (SprintStatus)<Sthis->line(v tests/Unit/Component/ES/Processor/DTOs/SelectionListTest.php +@а -5.84 +5.140 %dnamespace Tests\Unit\Component\ES\Processor\DT0s;use Jiminny\Component\ES\Processor\DT0s\SelectionList;use PHPUnit\Framework\Attributes\CoversClass;use PHPUnit Framework TestCase:#[CoversClass(SelectionList::class)]|final class Selectionl ictTect eytends TectCasepublic function testGetEntityIds(): void• Enter a prompt for GeminiProvYour Jiminny chats aren't used to improve our models. Gemini is Al. It can make mistakes, so double check it. Your privacy & GeminiSummarize page"Dally - Platrorm• in om100% C7 • Tue 19 May 9:40:16• 0 18 viewed• Awaiting approval+5 -1 0000Vieweduse J1minnv componentES Processor Traits ValidateUodatelargettra1t:use Jiminny\Component\ES\Processor\UpdateTarget;12 + use Jiminny\Component\ES\QueuePriorityEnum;use Jiminny\Component\ES\Repositories\EsResetRepositoryInterface;146148149150152use Jimanny\Exceptions\Inval1dArgumentException;use Jiminny\Traits\GracefullyStoppable;private function getRemainingScheduledEntities(bool SprintStatus = talse): 1ntSremainingReqular = AsyncUpdateElasticSearch::qetEntitiesListcount(Sthis->updateTarget);SremaininaPriority = AsvncUpdateElasticSearch::qetEntitiesListcountlSthis->updateTaraet.QueuePriorityEnum: :HIGHif (SprintStatus) {Sthis-sline(+103 -47 aaae Viewednamesnace Testslllnit\Connonent\FS\Processor\DT0c•use Jiminny\Component\ES\Processor\DT0s\SelectionList;+ use Jiminny ComponentES QueuePriorityEnum:use PHPUnit\Framework\Attributes\CoversClass;use PHPUnit\Framework\TestCase:#CoversClass(SelectionList::class)]|final clacs Selectionl istTect extends TectCasenrivate conct int CHINK ST7F = 109•publie function testAdEntAEyLIStAnGetAL LI8St): Vos$selectionList = new SelectionList();SselectionList->addEntitvList(OueuePrioritvEnum::HIGH. [1. 21):SselectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);Sthis->assertSame([1, 2, 3, 4], $selectionList->getAllIds());...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
55687
|
1933
|
15
|
2026-05-19T06:40:19.168971+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779172819168_m2.jpg...
|
Firefox
|
NULL
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
HomeActivityMoreslackcalVIewMistonWindowHelp@ Desc HomeActivityMoreslackcalVIewMistonWindowHelp@ Describe what you are looking forJiminny ...# platform-tickets# product launchesac random# releases# sofia-office# support# thank-yous# the_people_of jimi..•? Direct messages* Vasil VasilevGalya Dimitro.f Aneliva Angelovaf. Nikolay Yankov& Stefka StovanovaStovan Tomovea Todor Stamatov MN Mario GeorgievNikolay Ivanova James Grahamo Stoyan Tanevea Stelivan Georgievf Petko KashinskiLukas Kovalik y...::: Apps" Jira Cloud8 Toast# engineering8 24MessagesCanvase FilesMoreFriday. May 15thYesterday ~llan Kvuchukoy 4:26 PM@here please don't denloy in the next 15mins, we need a release to go through fonJllan Kvuchukov 5-7 PMDeblovs are onen again.Circlec APP 9•31 AM• 1. PR with vulnerability hxes is ready forreviewPlease take a look at the code and conhrmthat evervthing works pronerly on vourlocal machine or on a nanet environmentiPull requests (iminny aoo)•#12097 hx/securitv: nom denendencvuodates - 2026-05-19 (secfix/nom-20260519)1Vew workilow runMessage #engineering+ Aaliff_1Qa70dQQ/Q7caf7fc27ech1dhacah5a20d871822caa0dh0r71004057c28c87afomponent/ES/Listeners/eMultiple largetsListener.phpes changed: ¿ adcitions ‹ celetion87 OpenJY-20808 low orioritv indexing queue #12082|Vasil-Jiminny wants to merge 36 commits into master from JY-20808-low-priority-indexing-queue• Filter files.....v • app• — Component/ES|v ListenersI* UpdateMultipleTargetsListen..# UpdateSingleTargetListener..• { Processorv ActionsE UpsertDocumentsAction.phpv / DTOs* SelectionList.php• ^ Traits# SelectEntitvListTrait.ohv* TargetEntitiesSelector.phpE1 AsvncUpdateElasticSearch.ohp# QueuePriorityEnum.ohp* UpdateProcessManager.phpv ^ Console/Commands/Elasticsear….+ AsvnclIndateFsFntities.nhn₴ ResetAsyncElasticSearchCom..> Ea tests/Unit/Component/ES|app/Console/Commands/Elasticsearch/ResetAsyncElasticSearchCommand.php Cuse Jiminny component ES Processor Traits Val1dateUodatelargettra1t:use Jamanny ycomponentics rrocessorupadtelarget,use Jiminny\Component\ES\Repositories\EsResetRepositoryInterface;use Jiminny\Exceptions\Inval1dArgumentException;use Jiminny\Traits\GracefullyStoppable;Ca -144,7 +145,10 @a private function shouldResetElasticSearchInternals(): void144private tunction getRemainingScheduledEntities(bool SprintStatus = talse): intSremainingReqular = AsyncUpdateElasticSearch::getEntitiesListcountSthis->updateTarget);SremainingPriority = AsvncUpdateElasticSearch::getEntitiesListCount(Sthis->updateTarget, true);148if (SprintStatus)<Sthis->line(v tests/Unit/Component/ES/Processor/DTOs/SelectionListTest.php +@а -5.84 +5.140 %dnamespace Tests\Unit\Component\ES\Processor\DT0s;use Jiminny\Component\ES\Processor\DT0s\SelectionList;use PHPUnit\Framework\Attributes\CoversClass;use PHPUnit Framework TestCase:#[CoversClass(SelectionList::class)]|final class Selectionl ictTect extends TectCasepublic function testGetEntityIds(): void• Enter a prompt for GeminiProvYour Jiminny chats aren't used to improve our models. Gemini is Al. It can make mistakes, so double check it. Your privacy & GeminiSummarize page+"Dally - Platrorm• in om100% C7 • Tue 19 May 9:40:18• 0 18 viewed•Awaiting approval+5 -1 0000Vieweduse J1minnv componentES Processor Traits ValidateUodatelargettrait:use Jiminny\Component\ES\Processor\UpdateTarget;12 + use Jiminny\Component\ES\QueuePriorityEnum;use Jiminny\Component\ES\Repositories\EsResetRepositoryInterface;146148149150152use Jimanny\Exceptions\Inval1dArgumentException;use Jiminny\Traits\GracefullyStoppable;private function getRemainingScheduledEntities(bool SprintStatus = talse): 1ntSremainingReqular = AsyncUpdateElasticSearch::qetEntitiesListcount(Sthis->updateTarget);SremaininaPriority = AsvncUpdateElasticSearch::qetEntitiesListcountlSthis->updateTaraet.QueuePriorityEnum: :HIGHif (SprintStatus) {Sthis-sline(+103 -47 aaae Viewednamesnace Tests\linit\Comnonent\FS\Procecsor\DT0s:use Jiminny\Component\ES\Processor\DT0s\SelectionList;+ use Jiminny ComponentES QueuePriorityEnum:use PHPUnit\Framework\Attributes\CoversClass;use PHPUnit\Framework\TestCase:#CoversClass(SelectionList::class)]|final clacs Selectionl istTect extends TectCasenrivate conct int CHINK ST7F = 109•publie function testAdEntAEyLIStAnGetAL LI8St): Vos$selectionList = new SelectionList();SselectionList->addEntitvList(OueuePrioritvEnum::HIGH. [1. 21):SselectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);Sthis->assertSame([1, 2, 3, 4], $selectionList->getAllIds());...
|
NULL
|
-2997674397601544197
|
NULL
|
click
|
ocr
|
NULL
|
HomeActivityMoreslackcalVIewMistonWindowHelp@ Desc HomeActivityMoreslackcalVIewMistonWindowHelp@ Describe what you are looking forJiminny ...# platform-tickets# product launchesac random# releases# sofia-office# support# thank-yous# the_people_of jimi..•? Direct messages* Vasil VasilevGalya Dimitro.f Aneliva Angelovaf. Nikolay Yankov& Stefka StovanovaStovan Tomovea Todor Stamatov MN Mario GeorgievNikolay Ivanova James Grahamo Stoyan Tanevea Stelivan Georgievf Petko KashinskiLukas Kovalik y...::: Apps" Jira Cloud8 Toast# engineering8 24MessagesCanvase FilesMoreFriday. May 15thYesterday ~llan Kvuchukoy 4:26 PM@here please don't denloy in the next 15mins, we need a release to go through fonJllan Kvuchukov 5-7 PMDeblovs are onen again.Circlec APP 9•31 AM• 1. PR with vulnerability hxes is ready forreviewPlease take a look at the code and conhrmthat evervthing works pronerly on vourlocal machine or on a nanet environmentiPull requests (iminny aoo)•#12097 hx/securitv: nom denendencvuodates - 2026-05-19 (secfix/nom-20260519)1Vew workilow runMessage #engineering+ Aaliff_1Qa70dQQ/Q7caf7fc27ech1dhacah5a20d871822caa0dh0r71004057c28c87afomponent/ES/Listeners/eMultiple largetsListener.phpes changed: ¿ adcitions ‹ celetion87 OpenJY-20808 low orioritv indexing queue #12082|Vasil-Jiminny wants to merge 36 commits into master from JY-20808-low-priority-indexing-queue• Filter files.....v • app• — Component/ES|v ListenersI* UpdateMultipleTargetsListen..# UpdateSingleTargetListener..• { Processorv ActionsE UpsertDocumentsAction.phpv / DTOs* SelectionList.php• ^ Traits# SelectEntitvListTrait.ohv* TargetEntitiesSelector.phpE1 AsvncUpdateElasticSearch.ohp# QueuePriorityEnum.ohp* UpdateProcessManager.phpv ^ Console/Commands/Elasticsear….+ AsvnclIndateFsFntities.nhn₴ ResetAsyncElasticSearchCom..> Ea tests/Unit/Component/ES|app/Console/Commands/Elasticsearch/ResetAsyncElasticSearchCommand.php Cuse Jiminny component ES Processor Traits Val1dateUodatelargettra1t:use Jamanny ycomponentics rrocessorupadtelarget,use Jiminny\Component\ES\Repositories\EsResetRepositoryInterface;use Jiminny\Exceptions\Inval1dArgumentException;use Jiminny\Traits\GracefullyStoppable;Ca -144,7 +145,10 @a private function shouldResetElasticSearchInternals(): void144private tunction getRemainingScheduledEntities(bool SprintStatus = talse): intSremainingReqular = AsyncUpdateElasticSearch::getEntitiesListcountSthis->updateTarget);SremainingPriority = AsvncUpdateElasticSearch::getEntitiesListCount(Sthis->updateTarget, true);148if (SprintStatus)<Sthis->line(v tests/Unit/Component/ES/Processor/DTOs/SelectionListTest.php +@а -5.84 +5.140 %dnamespace Tests\Unit\Component\ES\Processor\DT0s;use Jiminny\Component\ES\Processor\DT0s\SelectionList;use PHPUnit\Framework\Attributes\CoversClass;use PHPUnit Framework TestCase:#[CoversClass(SelectionList::class)]|final class Selectionl ictTect extends TectCasepublic function testGetEntityIds(): void• Enter a prompt for GeminiProvYour Jiminny chats aren't used to improve our models. Gemini is Al. It can make mistakes, so double check it. Your privacy & GeminiSummarize page+"Dally - Platrorm• in om100% C7 • Tue 19 May 9:40:18• 0 18 viewed•Awaiting approval+5 -1 0000Vieweduse J1minnv componentES Processor Traits ValidateUodatelargettrait:use Jiminny\Component\ES\Processor\UpdateTarget;12 + use Jiminny\Component\ES\QueuePriorityEnum;use Jiminny\Component\ES\Repositories\EsResetRepositoryInterface;146148149150152use Jimanny\Exceptions\Inval1dArgumentException;use Jiminny\Traits\GracefullyStoppable;private function getRemainingScheduledEntities(bool SprintStatus = talse): 1ntSremainingReqular = AsyncUpdateElasticSearch::qetEntitiesListcount(Sthis->updateTarget);SremaininaPriority = AsvncUpdateElasticSearch::qetEntitiesListcountlSthis->updateTaraet.QueuePriorityEnum: :HIGHif (SprintStatus) {Sthis-sline(+103 -47 aaae Viewednamesnace Tests\linit\Comnonent\FS\Procecsor\DT0s:use Jiminny\Component\ES\Processor\DT0s\SelectionList;+ use Jiminny ComponentES QueuePriorityEnum:use PHPUnit\Framework\Attributes\CoversClass;use PHPUnit\Framework\TestCase:#CoversClass(SelectionList::class)]|final clacs Selectionl istTect extends TectCasenrivate conct int CHINK ST7F = 109•publie function testAdEntAEyLIStAnGetAL LI8St): Vos$selectionList = new SelectionList();SselectionList->addEntitvList(OueuePrioritvEnum::HIGH. [1. 21):SselectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);Sthis->assertSame([1, 2, 3, 4], $selectionList->getAllIds());...
|
55686
|
NULL
|
NULL
|
NULL
|
|
55688
|
1933
|
16
|
2026-05-19T06:40:20.770243+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779172820770_m2.jpg...
|
Firefox
|
JY-20808 low priority indexing queue by Vasil-Jimi JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app — Work...
|
1
|
github.com/jiminny/app/pull/12082/changes#diff-49a github.com/jiminny/app/pull/12082/changes#diff-49a79d99c97caf7fc27ecb1dbacab5a29d871822caa0db0c71e94957c28c87af...
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
Close tab
New Tab
Customize sidebar
Close Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
AI Chat settings
Close
WORK, Google Account: [EMAIL]
Main menu
New chat
Gemini
New Chat
Open menu for conversation actions.
Conversation with Gemini
Conversation with Gemini
Show the uploaded image in a lightbox
Copy prompt
You said Make a PR of changes Find potential issues and bottlenecks
You said
Make a PR of changes Find potential issues and bottlenecks
Listen
Show thinking
Gemini said
Gemini said
I can see you've uploaded a screenshot of a code diff, likely from a version control system given the red and green highlights. I would love to help you review the changes, spot bottlenecks, and help you draft a Pull Request.
However,
the image resolution is far too low for me to read.
It appears to be a completely zoomed-out view where the code has been reduced to tiny, illegible pixels. Because of this, I cannot extract any text or logic to analyze.
How You Can Share the Code
How You Can Share the Code
To help me review your code effectively, please try one of the following:
Paste the text directly:
Copy the specific code blocks (both the old and new versions if possible) and paste them directly into our chat.
Upload the files:
If the changes are extensive, you can upload the raw text or code files.
Take high-resolution screenshots:
If you must use images, take closer, readable screenshots of the specific functions or methods you want me to review.
Once you provide the readable code, I can dive right in to identify potential bugs, assess performance bottlenecks, and help you summarize the changes for your PR!
Good response
Bad response
Share & export
Copy
Show more options
Copy prompt
Edit
You said app/Component/ES/Listeners/UpdateMultipleTargetsListener.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\Component\ES\Listeners; namespace Jiminny\Component\ES\Listeners; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Contracts\ES\Events\UpdateMultipleEntities; use Jiminny\Contracts\ES\Events\UpdateMultipleEntities; use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface; AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntities(), $event->getEntities(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } } } app/Component/ES/Listeners/UpdateSingleTargetListener.php +9-1Lines changed: 9 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Actions\TrackElasticSearchOperations; use Jiminny\Component\ES\Actions\TrackElasticSearchOperations; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Contracts\ES\Events\UpdateSingleEntity; use Jiminny\Contracts\ES\Events\UpdateSingleEntity; use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface; 'entityId' => $event->getEntityId(), 'entityId' => $event->getEntityId(), ]); ]); /** * @important: * Synchronous event should eventually be deprecated. * Instant write operations are blocking and should be used sparingly. * It is much better in terms of performance to write 100 or 1000 documents at once, * and have one blocking reindex operation, instead of writing 10 documents synchronously. */ if ($event->isSyncEvent()) { if ($event->isSyncEvent()) { $this->handleSyncEvent($event); $this->handleSyncEvent($event); AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntityId(), $event->getEntityId(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } app/Component/ES/Processor/Actions/UpsertDocumentsAction.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SimpleCollection; use Jiminny\Component\ES\Processor\DTOs\SimpleCollection; use Jiminny\Component\ES\Processor\ResponseEvaluator; use Jiminny\Component\ES\Processor\ResponseEvaluator; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Exceptions\InvalidDataException; use Jiminny\Exceptions\InvalidDataException; use Sentry\Laravel\Facade as Sentry; use Sentry\Laravel\Facade as Sentry; AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( entityType: $this->updateTarget, entityType: $this->updateTarget, entityId: (int) $document->getId(), entityId: (int) $document->getId(), withPriority: true priority: QueuePriorityEnum::HIGH, ); ); } } app/Component/ES/Processor/DTOs/SelectionList.php +54-17Lines changed: 54 additions & 17 deletions Original file line numberOriginal file lineDiff line numberDiff line change namespace Jiminny\Component\ES\Processor\DTOs; namespace Jiminny\Component\ES\Processor\DTOs; use Jiminny\Component\ES\QueuePriorityEnum; /** /** * A very basic and simple collection of entity IDs. * A very basic and simple collection of entity IDs. */ */ class SelectionList class SelectionList { { public function __construct( private const int DEFAULT_CHUNK = 200; private readonly array $priorityEntityIdList = [], private readonly array $normalEntityIdList = [], private int $chunkSize = self::DEFAULT_CHUNK; private readonly bool $isStaleChunkSelected = false, private bool $isStaleChunkSelected = false; private readonly int $chunkSize = 200, private array $selectedEntityIds = []; ) { // Do nothing public function setChunkSize(int $chunkSize): void { $this->chunkSize = $chunkSize; } } public function getAllIds(): array public function markStale(): void { { return array_merge($this->priorityEntityIdList, $this->normalEntityIdList); $this->isStaleChunkSelected = true; } } public function count(): int public function addEntityList(string|QueuePriorityEnum $priority, array $entityIds): void { { return count($this->priorityEntityIdList) + count($this->normalEntityIdList); $priorityKey = $this->normalisePriority($priority); if (! array_key_exists($priorityKey, $this->selectedEntityIds)) { $this->selectedEntityIds[$priorityKey] = []; } $this->selectedEntityIds[$priorityKey] = array_merge($this->selectedEntityIds[$priorityKey], $entityIds); } } public function isEmpty(): bool /** * @return string[] */ public function getEntityListGroups(): array { { return empty($this->priorityEntityIdList) && empty($this->normalEntityIdList); return array_keys($this->selectedEntityIds); } } public function getHighPriorityEntityIds(): array public function getEntityListItemsByGroup(string|QueuePriorityEnum $priority): array { { return $this->priorityEntityIdList; $priorityKey = $this->normalisePriority($priority); return $this->selectedEntityIds[$priorityKey] ?? []; } } public function getNormalPriorityEntityId(): array public function getAllIds(): array { { return $this->normalEntityIdList; $allIds = []; foreach ($this->selectedEntityIds as $entityIds) { $allIds = array_merge($allIds, $entityIds); } return $allIds; } public function count(): int { return array_sum( array_map('count', $this->selectedEntityIds) ); } public function isEmpty(): bool { return $this->count() === 0; } } public function isStaleChunkSelected(): bool public function isStaleChunkSelected(): bool { { return $this->count() >= $this->chunkSize; return $this->count() >= $this->chunkSize; } } private function normalisePriority(string|QueuePriorityEnum $priority): string { return $priority instanceof QueuePriorityEnum ? $priority->value : $priority; } } } app/Component/ES/Processor/Traits/SelectEntityListTrait.php +27-4Lines changed: 27 additions & 4 deletions Original file line numberOriginal file lineDiff line numberDiff line change use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; /** /** * Build the correct source list name for the type of entity and priority * Build the correct source list name for the type of entity and priority */ */ trait SelectEntityListTrait trait SelectEntityListTrait { { /** * Highest priority queue for data requiring near-instant availability. * Very few entities should be added here, only when absolutely necessary. */ private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; /** * Normal priority queue for normal application operations. * Almost all update events should pass through this queue */ private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; protected static function selectTargetList(string $entityType, bool $withPriority = false): string /** { * Nonblocking low priority queue. This queue will be consumed only when there is nothing * with higher priority. * * This queue will be used for operations such as es:reset-async */ private const string ENTITIES_LOW_PRIORITIES_LIST = '%s-for-update-low'; protected static function selectTargetList( string $entityType, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { if (! in_array($entityType, UpdateTarget::allowedTargets())) { if (! in_array($entityType, UpdateTarget::allowedTargets())) { throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); } } if ($withPriority) { if ($priority->isHigh()) { Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); } } if ($priority->isLow()) { return sprintf(self::ENTITIES_LOW_PRIORITIES_LIST, $entityType); } return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); } } } } app/Component/ES/Processor/TargetEntitiesSelector.php +26-21Lines changed: 26 additions & 21 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SelectionList; use Jiminny\Component\ES\Processor\DTOs\SelectionList; use Jiminny\Component\ES\Processor\Traits\ExtractIdsTrait; use Jiminny\Component\ES\Processor\Traits\ExtractIdsTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\QueuePriorityEnum; /** /** * This class supplies a list of entities pending an update. * This class supplies a list of entities pending an update. public function select(): SelectionList public function select(): SelectionList { { $staleWorkEntityIds = $this->getStaleChunk(); $selectionList = new SelectionList(); $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $staleWorkEntityIds = $this->getStaleChunk(); if (count($staleWorkEntityIds) > 0) { if (count($staleWorkEntityIds) > 0) { return new SelectionList( /** priorityEntityIdList: $staleWorkEntityIds, * Stale chunks are treated as high priority isStaleChunkSelected: true, */ chunkSize: ChunkSize::getStaleChunkSize($this->updateTarget), $selectionList->markStale(); ); $selectionList->addEntityList(QueuePriorityEnum::HIGH, $staleWorkEntityIds); $selectionList->setChunkSize(ChunkSize::getStaleChunkSize($this->updateTarget)); return $selectionList; } } $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $selectionList->setChunkSize($mainChunkSize); $priorityEntityIdsList = $this->extractIdsFromSet( $priorityEntityIdsList = $this->extractIds(QueuePriorityEnum::HIGH, $mainChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, true), $selectionList->addEntityList(QueuePriorityEnum::HIGH, $priorityEntityIdsList); $mainChunkSize, ); $normalEntityIdsList = []; $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); if ($normalEntityChunkSize > 0) { if ($normalEntityChunkSize > 0) { $normalEntityIdsList = $this->extractIdsFromSet( $normalEntityIdsList = $this->extractIds(QueuePriorityEnum::NORMAL, $normalEntityChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, false), $selectionList->addEntityList(QueuePriorityEnum::NORMAL, $normalEntityIdsList); $normalEntityChunkSize ); } } return new SelectionList( return $selectionList; priorityEntityIdList: $priorityEntityIdsList, normalEntityIdList: $normalEntityIdsList, chunkSize: $mainChunkSize ); } } private function getStaleChunk(): array private function getStaleChunk(): array return []; return []; } } private function extractIds(QueuePriorityEnum $priority, int $chunkSize): array { return $this->extractIdsFromSet( AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, $priority), $chunkSize ); } } } app/Component/ES/AsyncUpdateElasticSearch.php +17-10Lines changed: 17 additions & 10 deletions Original file line numberOriginal file lineDiff line numberDiff line change * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * and other activity related data * and other activity related data */ */ public static function markEntityForUpdate(string $entityType, int $entityId, bool $withPriority = false): void public static function markEntityForUpdate( { string $entityType, $targetList = self::selectTargetList($entityType, $withPriority); int $entityId, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { $targetList = self::selectTargetList($entityType, $priority); Redis::sadd($targetList, $entityId); Redis::sadd($targetList, $entityId); Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ 'entityType' => $entityType, 'entityType' => $entityType, 'entityId' => $entityId, 'entityId' => $entityId, 'collectionKey' => $targetList, 'collectionKey' => $targetList, 'withPriority' => $withPriority, 'priority' => $priority->value, ]); ]); } } public static function bulkMarkEntitiesForUpdate( public static function bulkMarkEntitiesForUpdate( string $entityType, string $entityType, array $entityIds, array $entityIds, bool $withPriority = false QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { ): void { if (empty($entityIds)) { if (empty($entityIds)) { return; return; } } $targetList = self::selectTargetList($entityType, $withPriority); $targetList = self::selectTargetList($entityType, $priority); Redis::saddarray($targetList, $entityIds); Redis::saddarray($targetList, $entityIds); } } * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Takes priority into consideration. * Takes priority into consideration. */ */ public static function getEntitiesSourceList(string $updateTarget, $priority = false): string public static function getEntitiesSourceList( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { return self::selectTargetList($updateTarget, $priority); return self::selectTargetList($updateTarget, $priority); } } /** /** * Externally called helper methods * Externally called helper methods * - count and flush * - count and flush */ */ public static function getEntitiesListCount(string $updateTarget, $priority = false): int public static function getEntitiesListCount( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): int { $targetList = self::selectTargetList($updateTarget, $priority); $targetList = self::selectTargetList($updateTarget, $priority); return Redis::scard($targetList); return Redis::scard($targetList); app/Component/ES/QueuePriorityEnum.php +40Lines changed: 40 additions & 0 deletions Original file line numberOriginal file lineDiff line numberDiff line change <?php declare(strict_types=1); namespace Jiminny\Component\ES; use Jiminny\Exceptions\InvalidArgumentException; enum QueuePriorityEnum: string { case HIGH = 'high'; case NORMAL = 'normal'; case LOW = 'low'; public static function tryFromString(string $value): self { if (! self::isValid($value)) { throw new InvalidArgumentException( sprintf('Invalid queue priority "%s" selected', $value) ); } return self::tryFrom($value); } public static function isValid(string $value): bool { return self::tryFrom($value) !== null; } public function isLow(): bool { return $this === self::LOW; } public function isHigh(): bool { return $this === self::HIGH; } } app/Component/ES/UpdateProcessManager.php +12-9Lines changed: 12 additions & 9 deletions Original file line numberOriginal file lineDiff line numberDiff line change if ($selectionList->isEmpty()) { if ($selectionList->isEmpty()) { return false; return false; } } /** /** * A stale chunk will always be smaller than a regular chunk. * A stale chunk will always be smaller than a regular chunk. * That doesn't mean there aren't any other scheduled entities for processing * That doesn't mean there aren't any other scheduled entities for processing private function rescheduleThrottledEntities(SelectionList $selectionList): void private function rescheduleThrottledEntities(SelectionList $selectionList): void { { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $groups = $selectionList->getEntityListGroups(); $this->updateTarget, foreach ($groups as $eachGroup) { $selectionList->getNormalPriorityEntityId() $groupEntityIds = $selectionList->getEntityListItemsByGroup($eachGroup); ); if (! empty($groupEntityIds)) { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $this->updateTarget, entityType: $this->updateTarget, $selectionList->getHighPriorityEntityIds(), entityIds: $groupEntityIds, true priority: QueuePriorityEnum::tryFromString($eachGroup) ); ); } } } } } } app/Console/Commands/Elasticsearch/AsyncUpdateEsEntities.php +9-3Lines changed: 9 additions & 3 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Illuminate\Support\Str; use Illuminate\Support\Str; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Component\ES\UpdateProcessManager; use Jiminny\Component\ES\UpdateProcessManager; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Traits\GracefullyStoppable; use Jiminny\Traits\GracefullyStoppable; Redis::set($gaugeLockName, true); Redis::set($gaugeLockName, true); Redis::expire($gaugeLockName, 60); Redis::expire($gaugeLockName, 60); $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::HIGH), ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update', $updateTarget), stat: sprintf('jiminny.%s-for-update', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::NORMAL), ); ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), stat: sprintf('jiminny.%s-for-update-low', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, true), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::LOW), ); ); } } app/Console/Commands/Elasticsearch/ResetAsyncElasticSearchCommand.php +5-1Lines changed: 5 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\Traits\ValidateUpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\ValidateUpdateTargetTrait; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Component\ES\Repositories\EsResetRepositoryInterface; use Jiminny\Component\ES\Repositories\EsResetRepositoryInterface; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Traits\GracefullyStoppable; use Jiminny\Traits\GracefullyStoppable; private function getRemainingScheduledEntities(bool $printStatus = false): int private function getRemainingScheduledEntities(bool $printStatus = false): int { { $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget, true); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount( $this->updateTarget, QueuePriorityEnum::HIGH ); if ($printStatus) { if ($printStatus) { $this->line( $this->line(
You said
app/Component/ES/Listeners/UpdateMultipleTargetsListener.php
+2-1Lines changed: 2 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\Component\ES\Listeners;
namespace Jiminny\Component\ES\Listeners;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\QueuePriorityEnum;
use Jiminny\Contracts\ES\Events\UpdateMultipleEntities;
use Jiminny\Contracts\ES\Events\UpdateMultipleEntities;
use Psr\Log\LoggerInterface;
use Psr\Log\LoggerInterface;
AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(
AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(
$event->getUpdateTargetValue(),
$event->getUpdateTargetValue(),
$event->getEntities(),
$event->getEntities(),
$event->isPriority()
$event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL,
);
);
}
}
}
}
app/Component/ES/Listeners/UpdateSingleTargetListener.php
+9-1Lines changed: 9 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Actions\TrackElasticSearchOperations;
use Jiminny\Component\ES\Actions\TrackElasticSearchOperations;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\Processor\EntityQueryBuilder;
use Jiminny\Component\ES\Processor\EntityQueryBuilder;
use Jiminny\Component\ES\QueuePriorityEnum;
use Jiminny\Contracts\ES\Events\UpdateSingleEntity;
use Jiminny\Contracts\ES\Events\UpdateSingleEntity;
use Psr\Log\LoggerInterface;
use Psr\Log\LoggerInterface;
'entityId' => $event->getEntityId(),
'entityId' => $event->getEntityId(),
]);
]);
/**
* @important:
* Synchronous event should eventually be deprecated.
* Instant write operations are blocking and should be used sparingly.
* It is much better in terms of performance to write 100 or 1000 documents at once,
* and have one blocking reindex operation, instead of writing 10 documents synchronously.
*/
if ($event->isSyncEvent()) {
if ($event->isSyncEvent()) {
$this->handleSyncEvent($event);
$this->handleSyncEvent($event);
AsyncUpdateElasticSearch::markEntityForUpdate(
AsyncUpdateElasticSearch::markEntityForUpdate(
$event->getUpdateTargetValue(),
$event->getUpdateTargetValue(),
$event->getEntityId(),
$event->getEntityId(),
$event->isPriority()
$event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL,
);
);
}
}
app/Component/ES/Processor/Actions/UpsertDocumentsAction.php
+2-1Lines changed: 2 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SimpleCollection;
use Jiminny\Component\ES\Processor\DTOs\SimpleCollection;
use Jiminny\Component\ES\Processor\ResponseEvaluator;
use Jiminny\Component\ES\Processor\ResponseEvaluator;
use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait;
use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait;
use Jiminny\Component\ES\QueuePriorityEnum;
use Jiminny\Exceptions\InvalidDataException;
use Jiminny\Exceptions\InvalidDataException;
use Sentry\Laravel\Facade as Sentry;
use Sentry\Laravel\Facade as Sentry;
AsyncUpdateElasticSearch::markEntityForUpdate(
AsyncUpdateElasticSearch::markEntityForUpdate(
entityType: $this->updateTarget,
entityType: $this->updateTarget,
entityId: (int) $document->getId(),
entityId: (int) $document->getId(),
withPriority: true
priority: QueuePriorityEnum::HIGH,
);
);
}
}
app/Component/ES/Processor/DTOs/SelectionList.php
+54-17Lines changed: 54 additions & 17 deletions
Original file line numberOriginal file lineDiff line numberDiff line change
namespace Jiminny\Component\ES\Processor\DTOs;
namespace Jiminny\Component\ES\Processor\DTOs;
use Jiminny\Component\ES\QueuePriorityEnum;
/**
/**
* A very basic and simple collection of entity IDs.
* A very basic and simple collection of entity IDs.
*/
*/
class SelectionList
class SelectionList
{
{
public function __construct(
private const int DEFAULT_CHUNK = 200;
private readonly array $priorityEntityIdList = [],
private readonly array $normalEntityIdList = [],
private int $chunkSize = self::DEFAULT_CHUNK;
private readonly bool $isStaleChunkSelected = false,
private bool $isStaleChunkSelected = false;
private readonly int $chunkSize = 200,
private array $selectedEntityIds = [];
) {
// Do nothing
public function setChunkSize(int $chunkSize): void
{...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira","depth":4,"bounds":{"left":0.0,"top":0.0518755,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.06304868,"width":0.10106383,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app","depth":4,"bounds":{"left":0.0,"top":0.08459697,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app","depth":5,"bounds":{"left":0.013297873,"top":0.09577015,"width":0.18816489,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app","depth":4,"bounds":{"left":0.0,"top":0.11731844,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app","depth":5,"bounds":{"left":0.013297873,"top":0.12849163,"width":0.15674867,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.06732048,"top":0.1245012,"width":0.007978723,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New Tab","depth":4,"bounds":{"left":0.0028257978,"top":0.15163608,"width":0.07413564,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"bounds":{"left":0.0028257978,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Close Google Gemini (⌃X)","depth":6,"bounds":{"left":0.013796543,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Tabs from other devices","depth":6,"bounds":{"left":0.024933511,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"bounds":{"left":0.036070477,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"bounds":{"left":0.04720745,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"AI Chat settings","depth":7,"bounds":{"left":0.35854387,"top":0.055067837,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Close","depth":7,"bounds":{"left":0.37051198,"top":0.055067837,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"WORK, Google Account: lukas.kovalik@jiminny.com","depth":12,"bounds":{"left":0.3678524,"top":0.103751,"width":0.013297873,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Main menu","depth":12,"bounds":{"left":0.08494016,"top":0.103751,"width":0.013297873,"height":0.031923383},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New chat","depth":12,"bounds":{"left":0.09823803,"top":0.10454908,"width":0.028590426,"height":0.030327214},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Gemini","depth":15,"bounds":{"left":0.1008976,"top":0.10973663,"width":0.021941489,"height":0.020351157},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"New Chat","depth":12,"bounds":{"left":0.33992687,"top":0.103751,"width":0.013297873,"height":0.031923383},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Open menu for conversation actions.","depth":12,"bounds":{"left":0.35322472,"top":0.103751,"width":0.013297873,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXHeading","text":"Conversation with Gemini","depth":15,"bounds":{"left":0.079288565,"top":0.14764565,"width":0.0003324468,"height":0.0007980846},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Conversation with Gemini","depth":16,"bounds":{"left":0.079288565,"top":0.15003991,"width":0.1200133,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Show the uploaded image in a lightbox","depth":21,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy prompt","depth":21,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"You said Make a PR of changes Find potential issues and bottlenecks","depth":21,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"You said","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Make a PR of changes Find potential issues and bottlenecks","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Listen","depth":22,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Show thinking","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Gemini said","depth":20,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Gemini said","depth":21,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"I can see you've uploaded a screenshot of a code diff, likely from a version control system given the red and green highlights. I would love to help you review the changes, spot bottlenecks, and help you draft a Pull Request.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"However,","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"the image resolution is far too low for me to read.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"It appears to be a completely zoomed-out view where the code has been reduced to tiny, illegible pixels. Because of this, I cannot extract any text or logic to analyze.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"How You Can Share the Code","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"How You Can Share the Code","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"To help me review your code effectively, please try one of the following:","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Paste the text directly:","depth":26,"bounds":{"left":0.12599733,"top":0.0,"width":0.059175532,"height":0.016360734},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Copy the specific code blocks (both the old and new versions if possible) and paste them directly into our chat.","depth":26,"bounds":{"left":0.12599733,"top":0.0,"width":0.21476063,"height":0.038707104},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Upload the files:","depth":26,"bounds":{"left":0.12599733,"top":0.0,"width":0.042220745,"height":0.016360734},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"If the changes are extensive, you can upload the raw text or code files.","depth":26,"bounds":{"left":0.16821809,"top":0.0,"width":0.17154256,"height":0.016360734},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Take high-resolution screenshots:","depth":26,"bounds":{"left":0.12599733,"top":0.008778931,"width":0.08843085,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"If you must use images, take closer, readable screenshots of the specific functions or methods you want me to review.","depth":26,"bounds":{"left":0.12599733,"top":0.008778931,"width":0.23021941,"height":0.038707104},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Once you provide the readable code, I can dive right in to identify potential bugs, assess performance bottlenecks, and help you summarize the changes for your PR!","depth":24,"bounds":{"left":0.11336436,"top":0.06624102,"width":0.24534574,"height":0.038707104},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Good response","depth":22,"bounds":{"left":0.1100399,"top":0.12290503,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Bad response","depth":22,"bounds":{"left":0.120678194,"top":0.12290503,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Share & export","depth":21,"bounds":{"left":0.13131648,"top":0.12290503,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy","depth":22,"bounds":{"left":0.1419548,"top":0.12290503,"width":0.010638298,"height":0.025538707},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Show more options","depth":21,"bounds":{"left":0.15259309,"top":0.12290503,"width":0.010638298,"height":0.025538707},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy prompt","depth":21,"bounds":{"left":0.17121011,"top":0.18355946,"width":0.013297873,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Edit","depth":21,"bounds":{"left":0.18583776,"top":0.18355946,"width":0.013297873,"height":0.031923383},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"You said app/Component/ES/Listeners/UpdateMultipleTargetsListener.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\\Component\\ES\\Listeners; namespace Jiminny\\Component\\ES\\Listeners; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Contracts\\ES\\Events\\UpdateMultipleEntities; use Jiminny\\Contracts\\ES\\Events\\UpdateMultipleEntities; use Psr\\Log\\LoggerInterface; use Psr\\Log\\LoggerInterface; AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntities(), $event->getEntities(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } } } app/Component/ES/Listeners/UpdateSingleTargetListener.php +9-1Lines changed: 9 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Actions\\TrackElasticSearchOperations; use Jiminny\\Component\\ES\\Actions\\TrackElasticSearchOperations; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder; use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Contracts\\ES\\Events\\UpdateSingleEntity; use Jiminny\\Contracts\\ES\\Events\\UpdateSingleEntity; use Psr\\Log\\LoggerInterface; use Psr\\Log\\LoggerInterface; 'entityId' => $event->getEntityId(), 'entityId' => $event->getEntityId(), ]); ]); /** * @important: * Synchronous event should eventually be deprecated. * Instant write operations are blocking and should be used sparingly. * It is much better in terms of performance to write 100 or 1000 documents at once, * and have one blocking reindex operation, instead of writing 10 documents synchronously. */ if ($event->isSyncEvent()) { if ($event->isSyncEvent()) { $this->handleSyncEvent($event); $this->handleSyncEvent($event); AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntityId(), $event->getEntityId(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } app/Component/ES/Processor/Actions/UpsertDocumentsAction.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Processor\\DTOs\\SimpleCollection; use Jiminny\\Component\\ES\\Processor\\DTOs\\SimpleCollection; use Jiminny\\Component\\ES\\Processor\\ResponseEvaluator; use Jiminny\\Component\\ES\\Processor\\ResponseEvaluator; use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait; use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Exceptions\\InvalidDataException; use Jiminny\\Exceptions\\InvalidDataException; use Sentry\\Laravel\\Facade as Sentry; use Sentry\\Laravel\\Facade as Sentry; AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( entityType: $this->updateTarget, entityType: $this->updateTarget, entityId: (int) $document->getId(), entityId: (int) $document->getId(), withPriority: true priority: QueuePriorityEnum::HIGH, ); ); } } app/Component/ES/Processor/DTOs/SelectionList.php +54-17Lines changed: 54 additions & 17 deletions Original file line numberOriginal file lineDiff line numberDiff line change namespace Jiminny\\Component\\ES\\Processor\\DTOs; namespace Jiminny\\Component\\ES\\Processor\\DTOs; use Jiminny\\Component\\ES\\QueuePriorityEnum; /** /** * A very basic and simple collection of entity IDs. * A very basic and simple collection of entity IDs. */ */ class SelectionList class SelectionList { { public function __construct( private const int DEFAULT_CHUNK = 200; private readonly array $priorityEntityIdList = [], private readonly array $normalEntityIdList = [], private int $chunkSize = self::DEFAULT_CHUNK; private readonly bool $isStaleChunkSelected = false, private bool $isStaleChunkSelected = false; private readonly int $chunkSize = 200, private array $selectedEntityIds = []; ) { // Do nothing public function setChunkSize(int $chunkSize): void { $this->chunkSize = $chunkSize; } } public function getAllIds(): array public function markStale(): void { { return array_merge($this->priorityEntityIdList, $this->normalEntityIdList); $this->isStaleChunkSelected = true; } } public function count(): int public function addEntityList(string|QueuePriorityEnum $priority, array $entityIds): void { { return count($this->priorityEntityIdList) + count($this->normalEntityIdList); $priorityKey = $this->normalisePriority($priority); if (! array_key_exists($priorityKey, $this->selectedEntityIds)) { $this->selectedEntityIds[$priorityKey] = []; } $this->selectedEntityIds[$priorityKey] = array_merge($this->selectedEntityIds[$priorityKey], $entityIds); } } public function isEmpty(): bool /** * @return string[] */ public function getEntityListGroups(): array { { return empty($this->priorityEntityIdList) && empty($this->normalEntityIdList); return array_keys($this->selectedEntityIds); } } public function getHighPriorityEntityIds(): array public function getEntityListItemsByGroup(string|QueuePriorityEnum $priority): array { { return $this->priorityEntityIdList; $priorityKey = $this->normalisePriority($priority); return $this->selectedEntityIds[$priorityKey] ?? []; } } public function getNormalPriorityEntityId(): array public function getAllIds(): array { { return $this->normalEntityIdList; $allIds = []; foreach ($this->selectedEntityIds as $entityIds) { $allIds = array_merge($allIds, $entityIds); } return $allIds; } public function count(): int { return array_sum( array_map('count', $this->selectedEntityIds) ); } public function isEmpty(): bool { return $this->count() === 0; } } public function isStaleChunkSelected(): bool public function isStaleChunkSelected(): bool { { return $this->count() >= $this->chunkSize; return $this->count() >= $this->chunkSize; } } private function normalisePriority(string|QueuePriorityEnum $priority): string { return $priority instanceof QueuePriorityEnum ? $priority->value : $priority; } } } app/Component/ES/Processor/Traits/SelectEntityListTrait.php +27-4Lines changed: 27 additions & 4 deletions Original file line numberOriginal file lineDiff line numberDiff line change use Illuminate\\Support\\Facades\\Log; use Illuminate\\Support\\Facades\\Log; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Exceptions\\InvalidArgumentException; use Jiminny\\Exceptions\\InvalidArgumentException; /** /** * Build the correct source list name for the type of entity and priority * Build the correct source list name for the type of entity and priority */ */ trait SelectEntityListTrait trait SelectEntityListTrait { { /** * Highest priority queue for data requiring near-instant availability. * Very few entities should be added here, only when absolutely necessary. */ private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; /** * Normal priority queue for normal application operations. * Almost all update events should pass through this queue */ private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; protected static function selectTargetList(string $entityType, bool $withPriority = false): string /** { * Nonblocking low priority queue. This queue will be consumed only when there is nothing * with higher priority. * * This queue will be used for operations such as es:reset-async */ private const string ENTITIES_LOW_PRIORITIES_LIST = '%s-for-update-low'; protected static function selectTargetList( string $entityType, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { if (! in_array($entityType, UpdateTarget::allowedTargets())) { if (! in_array($entityType, UpdateTarget::allowedTargets())) { throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); } } if ($withPriority) { if ($priority->isHigh()) { Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); } } if ($priority->isLow()) { return sprintf(self::ENTITIES_LOW_PRIORITIES_LIST, $entityType); } return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); } } } } app/Component/ES/Processor/TargetEntitiesSelector.php +26-21Lines changed: 26 additions & 21 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Processor\\DTOs\\SelectionList; use Jiminny\\Component\\ES\\Processor\\DTOs\\SelectionList; use Jiminny\\Component\\ES\\Processor\\Traits\\ExtractIdsTrait; use Jiminny\\Component\\ES\\Processor\\Traits\\ExtractIdsTrait; use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait; use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait; use Jiminny\\Component\\ES\\QueuePriorityEnum; /** /** * This class supplies a list of entities pending an update. * This class supplies a list of entities pending an update. public function select(): SelectionList public function select(): SelectionList { { $staleWorkEntityIds = $this->getStaleChunk(); $selectionList = new SelectionList(); $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $staleWorkEntityIds = $this->getStaleChunk(); if (count($staleWorkEntityIds) > 0) { if (count($staleWorkEntityIds) > 0) { return new SelectionList( /** priorityEntityIdList: $staleWorkEntityIds, * Stale chunks are treated as high priority isStaleChunkSelected: true, */ chunkSize: ChunkSize::getStaleChunkSize($this->updateTarget), $selectionList->markStale(); ); $selectionList->addEntityList(QueuePriorityEnum::HIGH, $staleWorkEntityIds); $selectionList->setChunkSize(ChunkSize::getStaleChunkSize($this->updateTarget)); return $selectionList; } } $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $selectionList->setChunkSize($mainChunkSize); $priorityEntityIdsList = $this->extractIdsFromSet( $priorityEntityIdsList = $this->extractIds(QueuePriorityEnum::HIGH, $mainChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, true), $selectionList->addEntityList(QueuePriorityEnum::HIGH, $priorityEntityIdsList); $mainChunkSize, ); $normalEntityIdsList = []; $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); if ($normalEntityChunkSize > 0) { if ($normalEntityChunkSize > 0) { $normalEntityIdsList = $this->extractIdsFromSet( $normalEntityIdsList = $this->extractIds(QueuePriorityEnum::NORMAL, $normalEntityChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, false), $selectionList->addEntityList(QueuePriorityEnum::NORMAL, $normalEntityIdsList); $normalEntityChunkSize ); } } return new SelectionList( return $selectionList; priorityEntityIdList: $priorityEntityIdsList, normalEntityIdList: $normalEntityIdsList, chunkSize: $mainChunkSize ); } } private function getStaleChunk(): array private function getStaleChunk(): array return []; return []; } } private function extractIds(QueuePriorityEnum $priority, int $chunkSize): array { return $this->extractIdsFromSet( AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, $priority), $chunkSize ); } } } app/Component/ES/AsyncUpdateElasticSearch.php +17-10Lines changed: 17 additions & 10 deletions Original file line numberOriginal file lineDiff line numberDiff line change * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * and other activity related data * and other activity related data */ */ public static function markEntityForUpdate(string $entityType, int $entityId, bool $withPriority = false): void public static function markEntityForUpdate( { string $entityType, $targetList = self::selectTargetList($entityType, $withPriority); int $entityId, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { $targetList = self::selectTargetList($entityType, $priority); Redis::sadd($targetList, $entityId); Redis::sadd($targetList, $entityId); Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ 'entityType' => $entityType, 'entityType' => $entityType, 'entityId' => $entityId, 'entityId' => $entityId, 'collectionKey' => $targetList, 'collectionKey' => $targetList, 'withPriority' => $withPriority, 'priority' => $priority->value, ]); ]); } } public static function bulkMarkEntitiesForUpdate( public static function bulkMarkEntitiesForUpdate( string $entityType, string $entityType, array $entityIds, array $entityIds, bool $withPriority = false QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { ): void { if (empty($entityIds)) { if (empty($entityIds)) { return; return; } } $targetList = self::selectTargetList($entityType, $withPriority); $targetList = self::selectTargetList($entityType, $priority); Redis::saddarray($targetList, $entityIds); Redis::saddarray($targetList, $entityIds); } } * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Takes priority into consideration. * Takes priority into consideration. */ */ public static function getEntitiesSourceList(string $updateTarget, $priority = false): string public static function getEntitiesSourceList( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { return self::selectTargetList($updateTarget, $priority); return self::selectTargetList($updateTarget, $priority); } } /** /** * Externally called helper methods * Externally called helper methods * - count and flush * - count and flush */ */ public static function getEntitiesListCount(string $updateTarget, $priority = false): int public static function getEntitiesListCount( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): int { $targetList = self::selectTargetList($updateTarget, $priority); $targetList = self::selectTargetList($updateTarget, $priority); return Redis::scard($targetList); return Redis::scard($targetList); app/Component/ES/QueuePriorityEnum.php +40Lines changed: 40 additions & 0 deletions Original file line numberOriginal file lineDiff line numberDiff line change <?php declare(strict_types=1); namespace Jiminny\\Component\\ES; use Jiminny\\Exceptions\\InvalidArgumentException; enum QueuePriorityEnum: string { case HIGH = 'high'; case NORMAL = 'normal'; case LOW = 'low'; public static function tryFromString(string $value): self { if (! self::isValid($value)) { throw new InvalidArgumentException( sprintf('Invalid queue priority \"%s\" selected', $value) ); } return self::tryFrom($value); } public static function isValid(string $value): bool { return self::tryFrom($value) !== null; } public function isLow(): bool { return $this === self::LOW; } public function isHigh(): bool { return $this === self::HIGH; } } app/Component/ES/UpdateProcessManager.php +12-9Lines changed: 12 additions & 9 deletions Original file line numberOriginal file lineDiff line numberDiff line change if ($selectionList->isEmpty()) { if ($selectionList->isEmpty()) { return false; return false; } } /** /** * A stale chunk will always be smaller than a regular chunk. * A stale chunk will always be smaller than a regular chunk. * That doesn't mean there aren't any other scheduled entities for processing * That doesn't mean there aren't any other scheduled entities for processing private function rescheduleThrottledEntities(SelectionList $selectionList): void private function rescheduleThrottledEntities(SelectionList $selectionList): void { { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $groups = $selectionList->getEntityListGroups(); $this->updateTarget, foreach ($groups as $eachGroup) { $selectionList->getNormalPriorityEntityId() $groupEntityIds = $selectionList->getEntityListItemsByGroup($eachGroup); ); if (! empty($groupEntityIds)) { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $this->updateTarget, entityType: $this->updateTarget, $selectionList->getHighPriorityEntityIds(), entityIds: $groupEntityIds, true priority: QueuePriorityEnum::tryFromString($eachGroup) ); ); } } } } } } app/Console/Commands/Elasticsearch/AsyncUpdateEsEntities.php +9-3Lines changed: 9 additions & 3 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Illuminate\\Support\\Str; use Illuminate\\Support\\Str; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Component\\ES\\UpdateProcessManager; use Jiminny\\Component\\ES\\UpdateProcessManager; use Jiminny\\Exceptions\\InvalidArgumentException; use Jiminny\\Exceptions\\InvalidArgumentException; use Jiminny\\Traits\\GracefullyStoppable; use Jiminny\\Traits\\GracefullyStoppable; Redis::set($gaugeLockName, true); Redis::set($gaugeLockName, true); Redis::expire($gaugeLockName, 60); Redis::expire($gaugeLockName, 60); $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::HIGH), ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update', $updateTarget), stat: sprintf('jiminny.%s-for-update', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::NORMAL), ); ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), stat: sprintf('jiminny.%s-for-update-low', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, true), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::LOW), ); ); } } app/Console/Commands/Elasticsearch/ResetAsyncElasticSearchCommand.php +5-1Lines changed: 5 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder; use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder; use Jiminny\\Component\\ES\\Processor\\Traits\\ValidateUpdateTargetTrait; use Jiminny\\Component\\ES\\Processor\\Traits\\ValidateUpdateTargetTrait; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Component\\ES\\Repositories\\EsResetRepositoryInterface; use Jiminny\\Component\\ES\\Repositories\\EsResetRepositoryInterface; use Jiminny\\Exceptions\\InvalidArgumentException; use Jiminny\\Exceptions\\InvalidArgumentException; use Jiminny\\Traits\\GracefullyStoppable; use Jiminny\\Traits\\GracefullyStoppable; private function getRemainingScheduledEntities(bool $printStatus = false): int private function getRemainingScheduledEntities(bool $printStatus = false): int { { $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget, true); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount( $this->updateTarget, QueuePriorityEnum::HIGH ); if ($printStatus) { if ($printStatus) { $this->line( $this->line(","depth":21,"bounds":{"left":0.20578457,"top":0.19313647,"width":0.13696809,"height":0.09577015},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"You said","depth":23,"bounds":{"left":0.079288565,"top":0.19393456,"width":0.019946808,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app/Component/ES/Listeners/UpdateMultipleTargetsListener.php","depth":23,"bounds":{"left":0.20578457,"top":0.19473264,"width":0.084773935,"height":0.035514764},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"+2-1Lines changed: 2 additions & 1 deletion","depth":23,"bounds":{"left":0.20578457,"top":0.25219473,"width":0.10388963,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\\Component\\ES\\Listeners;","depth":23,"bounds":{"left":0.20578457,"top":0.2905028,"width":0.11303192,"height":0.054668795},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"namespace Jiminny\\Component\\ES\\Listeners;","depth":23,"bounds":{"left":0.20578457,"top":0.34796488,"width":0.1100399,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch;","depth":23,"bounds":{"left":0.20578457,"top":0.40542698,"width":0.13380983,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch;","depth":23,"bounds":{"left":0.20578457,"top":0.424581,"width":0.13380983,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\QueuePriorityEnum;","depth":23,"bounds":{"left":0.20578457,"top":0.4820431,"width":0.115359046,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Contracts\\ES\\Events\\UpdateMultipleEntities;","depth":23,"bounds":{"left":0.20578457,"top":0.5011971,"width":0.13597074,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Contracts\\ES\\Events\\UpdateMultipleEntities;","depth":23,"bounds":{"left":0.20578457,"top":0.5203512,"width":0.13597074,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Psr\\Log\\LoggerInterface;","depth":23,"bounds":{"left":0.20578457,"top":0.5395052,"width":0.07047872,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Psr\\Log\\LoggerInterface;","depth":23,"bounds":{"left":0.20578457,"top":0.5586592,"width":0.07047872,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(","depth":23,"bounds":{"left":0.20578457,"top":0.6161213,"width":0.13530585,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(","depth":23,"bounds":{"left":0.20578457,"top":0.63527536,"width":0.13530585,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getUpdateTargetValue(),","depth":23,"bounds":{"left":0.20578457,"top":0.6544294,"width":0.0809508,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getUpdateTargetValue(),","depth":23,"bounds":{"left":0.20578457,"top":0.6735834,"width":0.0809508,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getEntities(),","depth":23,"bounds":{"left":0.20578457,"top":0.6927374,"width":0.052526597,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getEntities(),","depth":23,"bounds":{"left":0.20578457,"top":0.7118915,"width":0.052526597,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->isPriority()","depth":23,"bounds":{"left":0.20578457,"top":0.7310455,"width":0.046708778,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL,","depth":23,"bounds":{"left":0.20578457,"top":0.7501995,"width":0.11702128,"height":0.035514764},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":");","depth":23,"bounds":{"left":0.20578457,"top":0.7885076,"width":0.0033244682,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":");","depth":23,"bounds":{"left":0.20578457,"top":0.8076616,"width":0.0033244682,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"bounds":{"left":0.20578457,"top":0.82681566,"width":0.0019946808,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"bounds":{"left":0.20578457,"top":0.8459697,"width":0.0019946808,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"bounds":{"left":0.20578457,"top":0.8651237,"width":0.0019946808,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"bounds":{"left":0.20578457,"top":0.88427776,"width":0.0019946808,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app/Component/ES/Listeners/UpdateSingleTargetListener.php","depth":23,"bounds":{"left":0.20578457,"top":0.9034318,"width":0.07762633,"height":0.035514764},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"+9-1Lines changed: 9 additions & 1 deletion","depth":23,"bounds":{"left":0.20578457,"top":0.96089387,"width":0.104222074,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Actions\\TrackElasticSearchOperations;","depth":23,"bounds":{"left":0.20578457,"top":0.9992019,"width":0.13480718,"height":0.0007981062},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Actions\\TrackElasticSearchOperations;","depth":23,"bounds":{"left":0.20578457,"top":1.0,"width":0.13480718,"height":-0.07581806},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\QueuePriorityEnum;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Contracts\\ES\\Events\\UpdateSingleEntity;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Contracts\\ES\\Events\\UpdateSingleEntity;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Psr\\Log\\LoggerInterface;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Psr\\Log\\LoggerInterface;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"'entityId' => $event->getEntityId(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"'entityId' => $event->getEntityId(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"]);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"]);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/**","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* @important:","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* Synchronous event should eventually be deprecated.","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* Instant write operations are blocking and should be used sparingly.","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* It is much better in terms of performance to write 100 or 1000 documents at once,","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* and have one blocking reindex operation, instead of writing 10 documents synchronously.","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"*/","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"if ($event->isSyncEvent()) {","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"if ($event->isSyncEvent()) {","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$this->handleSyncEvent($event);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$this->handleSyncEvent($event);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AsyncUpdateElasticSearch::markEntityForUpdate(","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AsyncUpdateElasticSearch::markEntityForUpdate(","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getUpdateTargetValue(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getUpdateTargetValue(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getEntityId(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getEntityId(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->isPriority()","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL,","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":");","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":");","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app/Component/ES/Processor/Actions/UpsertDocumentsAction.php","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"+2-1Lines changed: 2 additions & 1 deletion","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Processor\\DTOs\\SimpleCollection;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\DTOs\\SimpleCollection;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\ResponseEvaluator;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\ResponseEvaluator;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\QueuePriorityEnum;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Exceptions\\InvalidDataException;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Exceptions\\InvalidDataException;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Sentry\\Laravel\\Facade as Sentry;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Sentry\\Laravel\\Facade as Sentry;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AsyncUpdateElasticSearch::markEntityForUpdate(","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AsyncUpdateElasticSearch::markEntityForUpdate(","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"entityType: $this->updateTarget,","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"entityType: $this->updateTarget,","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"entityId: (int) $document->getId(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"entityId: (int) $document->getId(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"withPriority: true","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"priority: QueuePriorityEnum::HIGH,","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":");","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":");","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app/Component/ES/Processor/DTOs/SelectionList.php","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"+54-17Lines changed: 54 additions & 17 deletions","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Original file line numberOriginal file lineDiff line numberDiff line change","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"namespace Jiminny\\Component\\ES\\Processor\\DTOs;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"namespace Jiminny\\Component\\ES\\Processor\\DTOs;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\QueuePriorityEnum;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/**","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/**","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* A very basic and simple collection of entity IDs.","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* A very basic and simple collection of entity IDs.","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"*/","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"*/","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"class SelectionList","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"class SelectionList","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function __construct(","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private const int DEFAULT_CHUNK = 200;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private readonly array $priorityEntityIdList = [],","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private readonly array $normalEntityIdList = [],","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private int $chunkSize = self::DEFAULT_CHUNK;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private readonly bool $isStaleChunkSelected = false,","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private bool $isStaleChunkSelected = false;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private readonly int $chunkSize = 200,","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private array $selectedEntityIds = [];","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":") {","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"// Do nothing","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function setChunkSize(int $chunkSize): void","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"}]...
|
-4004785998182418234
|
-1127563140626703218
|
click
|
accessibility
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
Close tab
New Tab
Customize sidebar
Close Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
AI Chat settings
Close
WORK, Google Account: [EMAIL]
Main menu
New chat
Gemini
New Chat
Open menu for conversation actions.
Conversation with Gemini
Conversation with Gemini
Show the uploaded image in a lightbox
Copy prompt
You said Make a PR of changes Find potential issues and bottlenecks
You said
Make a PR of changes Find potential issues and bottlenecks
Listen
Show thinking
Gemini said
Gemini said
I can see you've uploaded a screenshot of a code diff, likely from a version control system given the red and green highlights. I would love to help you review the changes, spot bottlenecks, and help you draft a Pull Request.
However,
the image resolution is far too low for me to read.
It appears to be a completely zoomed-out view where the code has been reduced to tiny, illegible pixels. Because of this, I cannot extract any text or logic to analyze.
How You Can Share the Code
How You Can Share the Code
To help me review your code effectively, please try one of the following:
Paste the text directly:
Copy the specific code blocks (both the old and new versions if possible) and paste them directly into our chat.
Upload the files:
If the changes are extensive, you can upload the raw text or code files.
Take high-resolution screenshots:
If you must use images, take closer, readable screenshots of the specific functions or methods you want me to review.
Once you provide the readable code, I can dive right in to identify potential bugs, assess performance bottlenecks, and help you summarize the changes for your PR!
Good response
Bad response
Share & export
Copy
Show more options
Copy prompt
Edit
You said app/Component/ES/Listeners/UpdateMultipleTargetsListener.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\Component\ES\Listeners; namespace Jiminny\Component\ES\Listeners; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Contracts\ES\Events\UpdateMultipleEntities; use Jiminny\Contracts\ES\Events\UpdateMultipleEntities; use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface; AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntities(), $event->getEntities(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } } } app/Component/ES/Listeners/UpdateSingleTargetListener.php +9-1Lines changed: 9 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Actions\TrackElasticSearchOperations; use Jiminny\Component\ES\Actions\TrackElasticSearchOperations; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Contracts\ES\Events\UpdateSingleEntity; use Jiminny\Contracts\ES\Events\UpdateSingleEntity; use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface; 'entityId' => $event->getEntityId(), 'entityId' => $event->getEntityId(), ]); ]); /** * @important: * Synchronous event should eventually be deprecated. * Instant write operations are blocking and should be used sparingly. * It is much better in terms of performance to write 100 or 1000 documents at once, * and have one blocking reindex operation, instead of writing 10 documents synchronously. */ if ($event->isSyncEvent()) { if ($event->isSyncEvent()) { $this->handleSyncEvent($event); $this->handleSyncEvent($event); AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntityId(), $event->getEntityId(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } app/Component/ES/Processor/Actions/UpsertDocumentsAction.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SimpleCollection; use Jiminny\Component\ES\Processor\DTOs\SimpleCollection; use Jiminny\Component\ES\Processor\ResponseEvaluator; use Jiminny\Component\ES\Processor\ResponseEvaluator; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Exceptions\InvalidDataException; use Jiminny\Exceptions\InvalidDataException; use Sentry\Laravel\Facade as Sentry; use Sentry\Laravel\Facade as Sentry; AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( entityType: $this->updateTarget, entityType: $this->updateTarget, entityId: (int) $document->getId(), entityId: (int) $document->getId(), withPriority: true priority: QueuePriorityEnum::HIGH, ); ); } } app/Component/ES/Processor/DTOs/SelectionList.php +54-17Lines changed: 54 additions & 17 deletions Original file line numberOriginal file lineDiff line numberDiff line change namespace Jiminny\Component\ES\Processor\DTOs; namespace Jiminny\Component\ES\Processor\DTOs; use Jiminny\Component\ES\QueuePriorityEnum; /** /** * A very basic and simple collection of entity IDs. * A very basic and simple collection of entity IDs. */ */ class SelectionList class SelectionList { { public function __construct( private const int DEFAULT_CHUNK = 200; private readonly array $priorityEntityIdList = [], private readonly array $normalEntityIdList = [], private int $chunkSize = self::DEFAULT_CHUNK; private readonly bool $isStaleChunkSelected = false, private bool $isStaleChunkSelected = false; private readonly int $chunkSize = 200, private array $selectedEntityIds = []; ) { // Do nothing public function setChunkSize(int $chunkSize): void { $this->chunkSize = $chunkSize; } } public function getAllIds(): array public function markStale(): void { { return array_merge($this->priorityEntityIdList, $this->normalEntityIdList); $this->isStaleChunkSelected = true; } } public function count(): int public function addEntityList(string|QueuePriorityEnum $priority, array $entityIds): void { { return count($this->priorityEntityIdList) + count($this->normalEntityIdList); $priorityKey = $this->normalisePriority($priority); if (! array_key_exists($priorityKey, $this->selectedEntityIds)) { $this->selectedEntityIds[$priorityKey] = []; } $this->selectedEntityIds[$priorityKey] = array_merge($this->selectedEntityIds[$priorityKey], $entityIds); } } public function isEmpty(): bool /** * @return string[] */ public function getEntityListGroups(): array { { return empty($this->priorityEntityIdList) && empty($this->normalEntityIdList); return array_keys($this->selectedEntityIds); } } public function getHighPriorityEntityIds(): array public function getEntityListItemsByGroup(string|QueuePriorityEnum $priority): array { { return $this->priorityEntityIdList; $priorityKey = $this->normalisePriority($priority); return $this->selectedEntityIds[$priorityKey] ?? []; } } public function getNormalPriorityEntityId(): array public function getAllIds(): array { { return $this->normalEntityIdList; $allIds = []; foreach ($this->selectedEntityIds as $entityIds) { $allIds = array_merge($allIds, $entityIds); } return $allIds; } public function count(): int { return array_sum( array_map('count', $this->selectedEntityIds) ); } public function isEmpty(): bool { return $this->count() === 0; } } public function isStaleChunkSelected(): bool public function isStaleChunkSelected(): bool { { return $this->count() >= $this->chunkSize; return $this->count() >= $this->chunkSize; } } private function normalisePriority(string|QueuePriorityEnum $priority): string { return $priority instanceof QueuePriorityEnum ? $priority->value : $priority; } } } app/Component/ES/Processor/Traits/SelectEntityListTrait.php +27-4Lines changed: 27 additions & 4 deletions Original file line numberOriginal file lineDiff line numberDiff line change use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; /** /** * Build the correct source list name for the type of entity and priority * Build the correct source list name for the type of entity and priority */ */ trait SelectEntityListTrait trait SelectEntityListTrait { { /** * Highest priority queue for data requiring near-instant availability. * Very few entities should be added here, only when absolutely necessary. */ private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; /** * Normal priority queue for normal application operations. * Almost all update events should pass through this queue */ private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; protected static function selectTargetList(string $entityType, bool $withPriority = false): string /** { * Nonblocking low priority queue. This queue will be consumed only when there is nothing * with higher priority. * * This queue will be used for operations such as es:reset-async */ private const string ENTITIES_LOW_PRIORITIES_LIST = '%s-for-update-low'; protected static function selectTargetList( string $entityType, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { if (! in_array($entityType, UpdateTarget::allowedTargets())) { if (! in_array($entityType, UpdateTarget::allowedTargets())) { throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); } } if ($withPriority) { if ($priority->isHigh()) { Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); } } if ($priority->isLow()) { return sprintf(self::ENTITIES_LOW_PRIORITIES_LIST, $entityType); } return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); } } } } app/Component/ES/Processor/TargetEntitiesSelector.php +26-21Lines changed: 26 additions & 21 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SelectionList; use Jiminny\Component\ES\Processor\DTOs\SelectionList; use Jiminny\Component\ES\Processor\Traits\ExtractIdsTrait; use Jiminny\Component\ES\Processor\Traits\ExtractIdsTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\QueuePriorityEnum; /** /** * This class supplies a list of entities pending an update. * This class supplies a list of entities pending an update. public function select(): SelectionList public function select(): SelectionList { { $staleWorkEntityIds = $this->getStaleChunk(); $selectionList = new SelectionList(); $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $staleWorkEntityIds = $this->getStaleChunk(); if (count($staleWorkEntityIds) > 0) { if (count($staleWorkEntityIds) > 0) { return new SelectionList( /** priorityEntityIdList: $staleWorkEntityIds, * Stale chunks are treated as high priority isStaleChunkSelected: true, */ chunkSize: ChunkSize::getStaleChunkSize($this->updateTarget), $selectionList->markStale(); ); $selectionList->addEntityList(QueuePriorityEnum::HIGH, $staleWorkEntityIds); $selectionList->setChunkSize(ChunkSize::getStaleChunkSize($this->updateTarget)); return $selectionList; } } $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $selectionList->setChunkSize($mainChunkSize); $priorityEntityIdsList = $this->extractIdsFromSet( $priorityEntityIdsList = $this->extractIds(QueuePriorityEnum::HIGH, $mainChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, true), $selectionList->addEntityList(QueuePriorityEnum::HIGH, $priorityEntityIdsList); $mainChunkSize, ); $normalEntityIdsList = []; $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); if ($normalEntityChunkSize > 0) { if ($normalEntityChunkSize > 0) { $normalEntityIdsList = $this->extractIdsFromSet( $normalEntityIdsList = $this->extractIds(QueuePriorityEnum::NORMAL, $normalEntityChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, false), $selectionList->addEntityList(QueuePriorityEnum::NORMAL, $normalEntityIdsList); $normalEntityChunkSize ); } } return new SelectionList( return $selectionList; priorityEntityIdList: $priorityEntityIdsList, normalEntityIdList: $normalEntityIdsList, chunkSize: $mainChunkSize ); } } private function getStaleChunk(): array private function getStaleChunk(): array return []; return []; } } private function extractIds(QueuePriorityEnum $priority, int $chunkSize): array { return $this->extractIdsFromSet( AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, $priority), $chunkSize ); } } } app/Component/ES/AsyncUpdateElasticSearch.php +17-10Lines changed: 17 additions & 10 deletions Original file line numberOriginal file lineDiff line numberDiff line change * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * and other activity related data * and other activity related data */ */ public static function markEntityForUpdate(string $entityType, int $entityId, bool $withPriority = false): void public static function markEntityForUpdate( { string $entityType, $targetList = self::selectTargetList($entityType, $withPriority); int $entityId, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { $targetList = self::selectTargetList($entityType, $priority); Redis::sadd($targetList, $entityId); Redis::sadd($targetList, $entityId); Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ 'entityType' => $entityType, 'entityType' => $entityType, 'entityId' => $entityId, 'entityId' => $entityId, 'collectionKey' => $targetList, 'collectionKey' => $targetList, 'withPriority' => $withPriority, 'priority' => $priority->value, ]); ]); } } public static function bulkMarkEntitiesForUpdate( public static function bulkMarkEntitiesForUpdate( string $entityType, string $entityType, array $entityIds, array $entityIds, bool $withPriority = false QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { ): void { if (empty($entityIds)) { if (empty($entityIds)) { return; return; } } $targetList = self::selectTargetList($entityType, $withPriority); $targetList = self::selectTargetList($entityType, $priority); Redis::saddarray($targetList, $entityIds); Redis::saddarray($targetList, $entityIds); } } * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Takes priority into consideration. * Takes priority into consideration. */ */ public static function getEntitiesSourceList(string $updateTarget, $priority = false): string public static function getEntitiesSourceList( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { return self::selectTargetList($updateTarget, $priority); return self::selectTargetList($updateTarget, $priority); } } /** /** * Externally called helper methods * Externally called helper methods * - count and flush * - count and flush */ */ public static function getEntitiesListCount(string $updateTarget, $priority = false): int public static function getEntitiesListCount( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): int { $targetList = self::selectTargetList($updateTarget, $priority); $targetList = self::selectTargetList($updateTarget, $priority); return Redis::scard($targetList); return Redis::scard($targetList); app/Component/ES/QueuePriorityEnum.php +40Lines changed: 40 additions & 0 deletions Original file line numberOriginal file lineDiff line numberDiff line change <?php declare(strict_types=1); namespace Jiminny\Component\ES; use Jiminny\Exceptions\InvalidArgumentException; enum QueuePriorityEnum: string { case HIGH = 'high'; case NORMAL = 'normal'; case LOW = 'low'; public static function tryFromString(string $value): self { if (! self::isValid($value)) { throw new InvalidArgumentException( sprintf('Invalid queue priority "%s" selected', $value) ); } return self::tryFrom($value); } public static function isValid(string $value): bool { return self::tryFrom($value) !== null; } public function isLow(): bool { return $this === self::LOW; } public function isHigh(): bool { return $this === self::HIGH; } } app/Component/ES/UpdateProcessManager.php +12-9Lines changed: 12 additions & 9 deletions Original file line numberOriginal file lineDiff line numberDiff line change if ($selectionList->isEmpty()) { if ($selectionList->isEmpty()) { return false; return false; } } /** /** * A stale chunk will always be smaller than a regular chunk. * A stale chunk will always be smaller than a regular chunk. * That doesn't mean there aren't any other scheduled entities for processing * That doesn't mean there aren't any other scheduled entities for processing private function rescheduleThrottledEntities(SelectionList $selectionList): void private function rescheduleThrottledEntities(SelectionList $selectionList): void { { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $groups = $selectionList->getEntityListGroups(); $this->updateTarget, foreach ($groups as $eachGroup) { $selectionList->getNormalPriorityEntityId() $groupEntityIds = $selectionList->getEntityListItemsByGroup($eachGroup); ); if (! empty($groupEntityIds)) { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $this->updateTarget, entityType: $this->updateTarget, $selectionList->getHighPriorityEntityIds(), entityIds: $groupEntityIds, true priority: QueuePriorityEnum::tryFromString($eachGroup) ); ); } } } } } } app/Console/Commands/Elasticsearch/AsyncUpdateEsEntities.php +9-3Lines changed: 9 additions & 3 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Illuminate\Support\Str; use Illuminate\Support\Str; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Component\ES\UpdateProcessManager; use Jiminny\Component\ES\UpdateProcessManager; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Traits\GracefullyStoppable; use Jiminny\Traits\GracefullyStoppable; Redis::set($gaugeLockName, true); Redis::set($gaugeLockName, true); Redis::expire($gaugeLockName, 60); Redis::expire($gaugeLockName, 60); $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::HIGH), ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update', $updateTarget), stat: sprintf('jiminny.%s-for-update', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::NORMAL), ); ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), stat: sprintf('jiminny.%s-for-update-low', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, true), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::LOW), ); ); } } app/Console/Commands/Elasticsearch/ResetAsyncElasticSearchCommand.php +5-1Lines changed: 5 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\Traits\ValidateUpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\ValidateUpdateTargetTrait; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Component\ES\Repositories\EsResetRepositoryInterface; use Jiminny\Component\ES\Repositories\EsResetRepositoryInterface; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Traits\GracefullyStoppable; use Jiminny\Traits\GracefullyStoppable; private function getRemainingScheduledEntities(bool $printStatus = false): int private function getRemainingScheduledEntities(bool $printStatus = false): int { { $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget, true); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount( $this->updateTarget, QueuePriorityEnum::HIGH ); if ($printStatus) { if ($printStatus) { $this->line( $this->line(
You said
app/Component/ES/Listeners/UpdateMultipleTargetsListener.php
+2-1Lines changed: 2 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\Component\ES\Listeners;
namespace Jiminny\Component\ES\Listeners;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\QueuePriorityEnum;
use Jiminny\Contracts\ES\Events\UpdateMultipleEntities;
use Jiminny\Contracts\ES\Events\UpdateMultipleEntities;
use Psr\Log\LoggerInterface;
use Psr\Log\LoggerInterface;
AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(
AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(
$event->getUpdateTargetValue(),
$event->getUpdateTargetValue(),
$event->getEntities(),
$event->getEntities(),
$event->isPriority()
$event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL,
);
);
}
}
}
}
app/Component/ES/Listeners/UpdateSingleTargetListener.php
+9-1Lines changed: 9 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Actions\TrackElasticSearchOperations;
use Jiminny\Component\ES\Actions\TrackElasticSearchOperations;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\Processor\EntityQueryBuilder;
use Jiminny\Component\ES\Processor\EntityQueryBuilder;
use Jiminny\Component\ES\QueuePriorityEnum;
use Jiminny\Contracts\ES\Events\UpdateSingleEntity;
use Jiminny\Contracts\ES\Events\UpdateSingleEntity;
use Psr\Log\LoggerInterface;
use Psr\Log\LoggerInterface;
'entityId' => $event->getEntityId(),
'entityId' => $event->getEntityId(),
]);
]);
/**
* @important:
* Synchronous event should eventually be deprecated.
* Instant write operations are blocking and should be used sparingly.
* It is much better in terms of performance to write 100 or 1000 documents at once,
* and have one blocking reindex operation, instead of writing 10 documents synchronously.
*/
if ($event->isSyncEvent()) {
if ($event->isSyncEvent()) {
$this->handleSyncEvent($event);
$this->handleSyncEvent($event);
AsyncUpdateElasticSearch::markEntityForUpdate(
AsyncUpdateElasticSearch::markEntityForUpdate(
$event->getUpdateTargetValue(),
$event->getUpdateTargetValue(),
$event->getEntityId(),
$event->getEntityId(),
$event->isPriority()
$event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL,
);
);
}
}
app/Component/ES/Processor/Actions/UpsertDocumentsAction.php
+2-1Lines changed: 2 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SimpleCollection;
use Jiminny\Component\ES\Processor\DTOs\SimpleCollection;
use Jiminny\Component\ES\Processor\ResponseEvaluator;
use Jiminny\Component\ES\Processor\ResponseEvaluator;
use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait;
use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait;
use Jiminny\Component\ES\QueuePriorityEnum;
use Jiminny\Exceptions\InvalidDataException;
use Jiminny\Exceptions\InvalidDataException;
use Sentry\Laravel\Facade as Sentry;
use Sentry\Laravel\Facade as Sentry;
AsyncUpdateElasticSearch::markEntityForUpdate(
AsyncUpdateElasticSearch::markEntityForUpdate(
entityType: $this->updateTarget,
entityType: $this->updateTarget,
entityId: (int) $document->getId(),
entityId: (int) $document->getId(),
withPriority: true
priority: QueuePriorityEnum::HIGH,
);
);
}
}
app/Component/ES/Processor/DTOs/SelectionList.php
+54-17Lines changed: 54 additions & 17 deletions
Original file line numberOriginal file lineDiff line numberDiff line change
namespace Jiminny\Component\ES\Processor\DTOs;
namespace Jiminny\Component\ES\Processor\DTOs;
use Jiminny\Component\ES\QueuePriorityEnum;
/**
/**
* A very basic and simple collection of entity IDs.
* A very basic and simple collection of entity IDs.
*/
*/
class SelectionList
class SelectionList
{
{
public function __construct(
private const int DEFAULT_CHUNK = 200;
private readonly array $priorityEntityIdList = [],
private readonly array $normalEntityIdList = [],
private int $chunkSize = self::DEFAULT_CHUNK;
private readonly bool $isStaleChunkSelected = false,
private bool $isStaleChunkSelected = false;
private readonly int $chunkSize = 200,
private array $selectedEntityIds = [];
) {
// Do nothing
public function setChunkSize(int $chunkSize): void
{...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
55689
|
1933
|
17
|
2026-05-19T06:40:27.297347+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779172827297_m2.jpg...
|
Firefox
|
JY-20808 low priority indexing queue by Vasil-Jimi JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app — Work...
|
1
|
github.com/jiminny/app/pull/12082/changes#diff-49a github.com/jiminny/app/pull/12082/changes#diff-49a79d99c97caf7fc27ecb1dbacab5a29d871822caa0db0c71e94957c28c87af...
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
Close tab
New Tab
Customize sidebar
Close Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
AI Chat settings
Close
WORK, Google Account: [EMAIL]
Main menu
New chat
Gemini
New Chat
Open menu for conversation actions.
Conversation with Gemini
Conversation with Gemini
Show the uploaded image in a lightbox
Copy prompt
You said Make a PR of changes Find potential issues and bottlenecks
You said
Make a PR of changes Find potential issues and bottlenecks
Listen
Show thinking
Gemini said
Gemini said
I can see you've uploaded a screenshot of a code diff, likely from a version control system given the red and green highlights. I would love to help you review the changes, spot bottlenecks, and help you draft a Pull Request.
However,
the image resolution is far too low for me to read.
It appears to be a completely zoomed-out view where the code has been reduced to tiny, illegible pixels. Because of this, I cannot extract any text or logic to analyze.
How You Can Share the Code
How You Can Share the Code
To help me review your code effectively, please try one of the following:
Paste the text directly:
Copy the specific code blocks (both the old and new versions if possible) and paste them directly into our chat.
Upload the files:
If the changes are extensive, you can upload the raw text or code files.
Take high-resolution screenshots:
If you must use images, take closer, readable screenshots of the specific functions or methods you want me to review.
Once you provide the readable code, I can dive right in to identify potential bugs, assess performance bottlenecks, and help you summarize the changes for your PR!
Good response
Bad response
Share & export
Copy
Show more options
Copy prompt
Edit
You said app/Component/ES/Listeners/UpdateMultipleTargetsListener.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\Component\ES\Listeners; namespace Jiminny\Component\ES\Listeners; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Contracts\ES\Events\UpdateMultipleEntities; use Jiminny\Contracts\ES\Events\UpdateMultipleEntities; use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface; AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntities(), $event->getEntities(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } } } app/Component/ES/Listeners/UpdateSingleTargetListener.php +9-1Lines changed: 9 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Actions\TrackElasticSearchOperations; use Jiminny\Component\ES\Actions\TrackElasticSearchOperations; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Contracts\ES\Events\UpdateSingleEntity; use Jiminny\Contracts\ES\Events\UpdateSingleEntity; use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface; 'entityId' => $event->getEntityId(), 'entityId' => $event->getEntityId(), ]); ]); /** * @important: * Synchronous event should eventually be deprecated. * Instant write operations are blocking and should be used sparingly. * It is much better in terms of performance to write 100 or 1000 documents at once, * and have one blocking reindex operation, instead of writing 10 documents synchronously. */ if ($event->isSyncEvent()) { if ($event->isSyncEvent()) { $this->handleSyncEvent($event); $this->handleSyncEvent($event); AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntityId(), $event->getEntityId(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } app/Component/ES/Processor/Actions/UpsertDocumentsAction.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SimpleCollection; use Jiminny\Component\ES\Processor\DTOs\SimpleCollection; use Jiminny\Component\ES\Processor\ResponseEvaluator; use Jiminny\Component\ES\Processor\ResponseEvaluator; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Exceptions\InvalidDataException; use Jiminny\Exceptions\InvalidDataException; use Sentry\Laravel\Facade as Sentry; use Sentry\Laravel\Facade as Sentry; AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( entityType: $this->updateTarget, entityType: $this->updateTarget, entityId: (int) $document->getId(), entityId: (int) $document->getId(), withPriority: true priority: QueuePriorityEnum::HIGH, ); ); } } app/Component/ES/Processor/DTOs/SelectionList.php +54-17Lines changed: 54 additions & 17 deletions Original file line numberOriginal file lineDiff line numberDiff line change namespace Jiminny\Component\ES\Processor\DTOs; namespace Jiminny\Component\ES\Processor\DTOs; use Jiminny\Component\ES\QueuePriorityEnum; /** /** * A very basic and simple collection of entity IDs. * A very basic and simple collection of entity IDs. */ */ class SelectionList class SelectionList { { public function __construct( private const int DEFAULT_CHUNK = 200; private readonly array $priorityEntityIdList = [], private readonly array $normalEntityIdList = [], private int $chunkSize = self::DEFAULT_CHUNK; private readonly bool $isStaleChunkSelected = false, private bool $isStaleChunkSelected = false; private readonly int $chunkSize = 200, private array $selectedEntityIds = []; ) { // Do nothing public function setChunkSize(int $chunkSize): void { $this->chunkSize = $chunkSize; } } public function getAllIds(): array public function markStale(): void { { return array_merge($this->priorityEntityIdList, $this->normalEntityIdList); $this->isStaleChunkSelected = true; } } public function count(): int public function addEntityList(string|QueuePriorityEnum $priority, array $entityIds): void { { return count($this->priorityEntityIdList) + count($this->normalEntityIdList); $priorityKey = $this->normalisePriority($priority); if (! array_key_exists($priorityKey, $this->selectedEntityIds)) { $this->selectedEntityIds[$priorityKey] = []; } $this->selectedEntityIds[$priorityKey] = array_merge($this->selectedEntityIds[$priorityKey], $entityIds); } } public function isEmpty(): bool /** * @return string[] */ public function getEntityListGroups(): array { { return empty($this->priorityEntityIdList) && empty($this->normalEntityIdList); return array_keys($this->selectedEntityIds); } } public function getHighPriorityEntityIds(): array public function getEntityListItemsByGroup(string|QueuePriorityEnum $priority): array { { return $this->priorityEntityIdList; $priorityKey = $this->normalisePriority($priority); return $this->selectedEntityIds[$priorityKey] ?? []; } } public function getNormalPriorityEntityId(): array public function getAllIds(): array { { return $this->normalEntityIdList; $allIds = []; foreach ($this->selectedEntityIds as $entityIds) { $allIds = array_merge($allIds, $entityIds); } return $allIds; } public function count(): int { return array_sum( array_map('count', $this->selectedEntityIds) ); } public function isEmpty(): bool { return $this->count() === 0; } } public function isStaleChunkSelected(): bool public function isStaleChunkSelected(): bool { { return $this->count() >= $this->chunkSize; return $this->count() >= $this->chunkSize; } } private function normalisePriority(string|QueuePriorityEnum $priority): string { return $priority instanceof QueuePriorityEnum ? $priority->value : $priority; } } } app/Component/ES/Processor/Traits/SelectEntityListTrait.php +27-4Lines changed: 27 additions & 4 deletions Original file line numberOriginal file lineDiff line numberDiff line change use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; /** /** * Build the correct source list name for the type of entity and priority * Build the correct source list name for the type of entity and priority */ */ trait SelectEntityListTrait trait SelectEntityListTrait { { /** * Highest priority queue for data requiring near-instant availability. * Very few entities should be added here, only when absolutely necessary. */ private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; /** * Normal priority queue for normal application operations. * Almost all update events should pass through this queue */ private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; protected static function selectTargetList(string $entityType, bool $withPriority = false): string /** { * Nonblocking low priority queue. This queue will be consumed only when there is nothing * with higher priority. * * This queue will be used for operations such as es:reset-async */ private const string ENTITIES_LOW_PRIORITIES_LIST = '%s-for-update-low'; protected static function selectTargetList( string $entityType, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { if (! in_array($entityType, UpdateTarget::allowedTargets())) { if (! in_array($entityType, UpdateTarget::allowedTargets())) { throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); } } if ($withPriority) { if ($priority->isHigh()) { Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); } } if ($priority->isLow()) { return sprintf(self::ENTITIES_LOW_PRIORITIES_LIST, $entityType); } return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); } } } } app/Component/ES/Processor/TargetEntitiesSelector.php +26-21Lines changed: 26 additions & 21 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SelectionList; use Jiminny\Component\ES\Processor\DTOs\SelectionList; use Jiminny\Component\ES\Processor\Traits\ExtractIdsTrait; use Jiminny\Component\ES\Processor\Traits\ExtractIdsTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\QueuePriorityEnum; /** /** * This class supplies a list of entities pending an update. * This class supplies a list of entities pending an update. public function select(): SelectionList public function select(): SelectionList { { $staleWorkEntityIds = $this->getStaleChunk(); $selectionList = new SelectionList(); $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $staleWorkEntityIds = $this->getStaleChunk(); if (count($staleWorkEntityIds) > 0) { if (count($staleWorkEntityIds) > 0) { return new SelectionList( /** priorityEntityIdList: $staleWorkEntityIds, * Stale chunks are treated as high priority isStaleChunkSelected: true, */ chunkSize: ChunkSize::getStaleChunkSize($this->updateTarget), $selectionList->markStale(); ); $selectionList->addEntityList(QueuePriorityEnum::HIGH, $staleWorkEntityIds); $selectionList->setChunkSize(ChunkSize::getStaleChunkSize($this->updateTarget)); return $selectionList; } } $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $selectionList->setChunkSize($mainChunkSize); $priorityEntityIdsList = $this->extractIdsFromSet( $priorityEntityIdsList = $this->extractIds(QueuePriorityEnum::HIGH, $mainChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, true), $selectionList->addEntityList(QueuePriorityEnum::HIGH, $priorityEntityIdsList); $mainChunkSize, ); $normalEntityIdsList = []; $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); if ($normalEntityChunkSize > 0) { if ($normalEntityChunkSize > 0) { $normalEntityIdsList = $this->extractIdsFromSet( $normalEntityIdsList = $this->extractIds(QueuePriorityEnum::NORMAL, $normalEntityChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, false), $selectionList->addEntityList(QueuePriorityEnum::NORMAL, $normalEntityIdsList); $normalEntityChunkSize ); } } return new SelectionList( return $selectionList; priorityEntityIdList: $priorityEntityIdsList, normalEntityIdList: $normalEntityIdsList, chunkSize: $mainChunkSize ); } } private function getStaleChunk(): array private function getStaleChunk(): array return []; return []; } } private function extractIds(QueuePriorityEnum $priority, int $chunkSize): array { return $this->extractIdsFromSet( AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, $priority), $chunkSize ); } } } app/Component/ES/AsyncUpdateElasticSearch.php +17-10Lines changed: 17 additions & 10 deletions Original file line numberOriginal file lineDiff line numberDiff line change * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * and other activity related data * and other activity related data */ */ public static function markEntityForUpdate(string $entityType, int $entityId, bool $withPriority = false): void public static function markEntityForUpdate( { string $entityType, $targetList = self::selectTargetList($entityType, $withPriority); int $entityId, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { $targetList = self::selectTargetList($entityType, $priority); Redis::sadd($targetList, $entityId); Redis::sadd($targetList, $entityId); Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ 'entityType' => $entityType, 'entityType' => $entityType, 'entityId' => $entityId, 'entityId' => $entityId, 'collectionKey' => $targetList, 'collectionKey' => $targetList, 'withPriority' => $withPriority, 'priority' => $priority->value, ]); ]); } } public static function bulkMarkEntitiesForUpdate( public static function bulkMarkEntitiesForUpdate( string $entityType, string $entityType, array $entityIds, array $entityIds, bool $withPriority = false QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { ): void { if (empty($entityIds)) { if (empty($entityIds)) { return; return; } } $targetList = self::selectTargetList($entityType, $withPriority); $targetList = self::selectTargetList($entityType, $priority); Redis::saddarray($targetList, $entityIds); Redis::saddarray($targetList, $entityIds); } } * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Takes priority into consideration. * Takes priority into consideration. */ */ public static function getEntitiesSourceList(string $updateTarget, $priority = false): string public static function getEntitiesSourceList( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { return self::selectTargetList($updateTarget, $priority); return self::selectTargetList($updateTarget, $priority); } } /** /** * Externally called helper methods * Externally called helper methods * - count and flush * - count and flush */ */ public static function getEntitiesListCount(string $updateTarget, $priority = false): int public static function getEntitiesListCount( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): int { $targetList = self::selectTargetList($updateTarget, $priority); $targetList = self::selectTargetList($updateTarget, $priority); return Redis::scard($targetList); return Redis::scard($targetList); app/Component/ES/QueuePriorityEnum.php +40Lines changed: 40 additions & 0 deletions Original file line numberOriginal file lineDiff line numberDiff line change <?php declare(strict_types=1); namespace Jiminny\Component\ES; use Jiminny\Exceptions\InvalidArgumentException; enum QueuePriorityEnum: string { case HIGH = 'high'; case NORMAL = 'normal'; case LOW = 'low'; public static function tryFromString(string $value): self { if (! self::isValid($value)) { throw new InvalidArgumentException( sprintf('Invalid queue priority "%s" selected', $value) ); } return self::tryFrom($value); } public static function isValid(string $value): bool { return self::tryFrom($value) !== null; } public function isLow(): bool { return $this === self::LOW; } public function isHigh(): bool { return $this === self::HIGH; } } app/Component/ES/UpdateProcessManager.php +12-9Lines changed: 12 additions & 9 deletions Original file line numberOriginal file lineDiff line numberDiff line change if ($selectionList->isEmpty()) { if ($selectionList->isEmpty()) { return false; return false; } } /** /** * A stale chunk will always be smaller than a regular chunk. * A stale chunk will always be smaller than a regular chunk. * That doesn't mean there aren't any other scheduled entities for processing * That doesn't mean there aren't any other scheduled entities for processing private function rescheduleThrottledEntities(SelectionList $selectionList): void private function rescheduleThrottledEntities(SelectionList $selectionList): void { { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $groups = $selectionList->getEntityListGroups(); $this->updateTarget, foreach ($groups as $eachGroup) { $selectionList->getNormalPriorityEntityId() $groupEntityIds = $selectionList->getEntityListItemsByGroup($eachGroup); ); if (! empty($groupEntityIds)) { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $this->updateTarget, entityType: $this->updateTarget, $selectionList->getHighPriorityEntityIds(), entityIds: $groupEntityIds, true priority: QueuePriorityEnum::tryFromString($eachGroup) ); ); } } } } } } app/Console/Commands/Elasticsearch/AsyncUpdateEsEntities.php +9-3Lines changed: 9 additions & 3 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Illuminate\Support\Str; use Illuminate\Support\Str; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Component\ES\UpdateProcessManager; use Jiminny\Component\ES\UpdateProcessManager; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Traits\GracefullyStoppable; use Jiminny\Traits\GracefullyStoppable; Redis::set($gaugeLockName, true); Redis::set($gaugeLockName, true); Redis::expire($gaugeLockName, 60); Redis::expire($gaugeLockName, 60); $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::HIGH), ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update', $updateTarget), stat: sprintf('jiminny.%s-for-update', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::NORMAL), ); ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), stat: sprintf('jiminny.%s-for-update-low', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, true), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::LOW), ); ); } } app/Console/Commands/Elasticsearch/ResetAsyncElasticSearchCommand.php +5-1Lines changed: 5 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\Traits\ValidateUpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\ValidateUpdateTargetTrait; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Component\ES\Repositories\EsResetRepositoryInterface; use Jiminny\Component\ES\Repositories\EsResetRepositoryInterface; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Traits\GracefullyStoppable; use Jiminny\Traits\GracefullyStoppable; private function getRemainingScheduledEntities(bool $printStatus = false): int private function getRemainingScheduledEntities(bool $printStatus = false): int { { $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget, true); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount( $this->updateTarget, QueuePriorityEnum::HIGH ); if ($printStatus) { if ($printStatus) { $this->line( $this->line(
You said
app/Component/ES/Listeners/UpdateMultipleTargetsListener.php
+2-1Lines changed: 2 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\Component\ES\Listeners;
namespace Jiminny\Component\ES\Listeners;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\QueuePriorityEnum;
use Jiminny\Contracts\ES\Events\UpdateMultipleEntities;
use Jiminny\Contracts\ES\Events\UpdateMultipleEntities;
use Psr\Log\LoggerInterface;
use Psr\Log\LoggerInterface;
AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(
AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(
$event->getUpdateTargetValue(),
$event->getUpdateTargetValue(),
$event->getEntities(),
$event->getEntities(),
$event->isPriority()
$event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL,
);
);
}
}
}
}
app/Component/ES/Listeners/UpdateSingleTargetListener.php
+9-1Lines changed: 9 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Actions\TrackElasticSearchOperations;
use Jiminny\Component\ES\Actions\TrackElasticSearchOperations;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\Processor\EntityQueryBuilder;
use Jiminny\Component\ES\Processor\EntityQueryBuilder;
use Jiminny\Component\ES\QueuePriorityEnum;
use Jiminny\Contracts\ES\Events\UpdateSingleEntity;
use Jiminny\Contracts\ES\Events\UpdateSingleEntity;
use Psr\Log\LoggerInterface;
use Psr\Log\LoggerInterface;
'entityId' => $event->getEntityId(),
'entityId' => $event->getEntityId(),
]);
]);
/**
* @important:
* Synchronous event should eventually be deprecated.
* Instant write operations are blocking and should be used sparingly.
* It is much better in terms of performance to write 100 or 1000 documents at once,
* and have one blocking reindex operation, instead of writing 10 documents synchronously.
*/
if ($event->isSyncEvent()) {
if ($event->isSyncEvent()) {
$this->handleSyncEvent($event);
$this->handleSyncEvent($event);
AsyncUpdateElasticSearch::markEntityForUpdate(
AsyncUpdateElasticSearch::markEntityForUpdate(
$event->getUpdateTargetValue(),
$event->getUpdateTargetValue(),
$event->getEntityId(),
$event->getEntityId(),
$event->isPriority()
$event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL,
);
);
}
}
app/Component/ES/Processor/Actions/UpsertDocumentsAction.php
+2-1Lines changed: 2 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SimpleCollection;
use Jiminny\Component\ES\Processor\DTOs\SimpleCollection;
use Jiminny\Component\ES\Processor\ResponseEvaluator;
use Jiminny\Component\ES\Processor\ResponseEvaluator;
use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait;
use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait;
use Jiminny\Component\ES\QueuePriorityEnum;
use Jiminny\Exceptions\InvalidDataException;
use Jiminny\Exceptions\InvalidDataException;
use Sentry\Laravel\Facade as Sentry;
use Sentry\Laravel\Facade as Sentry;
AsyncUpdateElasticSearch::markEntityForUpdate(
AsyncUpdateElasticSearch::markEntityForUpdate(
entityType: $this->updateTarget,
entityType: $this->updateTarget,
entityId: (int) $document->getId(),
entityId: (int) $document->getId(),
withPriority: true
priority: QueuePriorityEnum::HIGH,
);
);
}
}
app/Component/ES/Processor/DTOs/SelectionList.php
+54-17Lines changed: 54 additions & 17 deletions
Original file line numberOriginal file lineDiff line numberDiff line change
namespace Jiminny\Component\ES\Processor\DTOs;
namespace Jiminny\Component\ES\Processor\DTOs;
use Jiminny\Component\ES\QueuePriorityEnum;
/**
/**
* A very basic and simple collection of entity IDs.
* A very basic and simple collection of entity IDs.
*/
*/
class SelectionList
class SelectionList
{
{
public function __construct(
private const int DEFAULT_CHUNK = 200;
private readonly array $priorityEntityIdList = [],
private readonly array $normalEntityIdList = [],
private int $chunkSize = self::DEFAULT_CHUNK;
private readonly bool $isStaleChunkSelected = false,
private bool $isStaleChunkSelected = false;
private readonly int $chunkSize = 200,
private array $selectedEntityIds = [];
) {
// Do nothing
public function setChunkSize(int $chunkSize): void
{
$this->chunkSize = $chunkSize;
}
}
public function getAllIds(): array
public function markStale(): void
{
{
return array_merge($this->priorityEntityIdList, $this->normalEntityIdList);
$this->isStaleChunkSelected = true;
}
}
public function count(): int
public function addEntityList(string|QueuePriorityEnum $priority, array $entityIds): void
{
{
return count($this->priorityEntityIdList) + count($this->normalEntityIdList);
$priorityKey = $this->normalisePriority($priority);
if (! array_key_exists($priorityKey, $this->selectedEntityIds)) {
$this->selectedEntityIds[$priorityKey] = [];
}
$this->selectedEntityIds[$priorityKey] = array_merge($this->selectedEntityIds[$priorityKey], $entityIds);
}
}
public function isEmpty(): bool
/**
* @return string[]
*/
public function getEntityListGroups(): array
{
{
return empty($this->priorityEntityIdList) && empty($this->normalEntityIdList);
return array_keys($this->selectedEntityIds);
}
}
public function getHighPriorityEntityIds(): array
public function getEntityListItemsByGroup(string|QueuePriorityEnum $priority): array
{
{
return $this->priorityEntityIdList;
$priorityKey = $this->normalisePriority($priority);
return $this->selectedEntityIds[$priorityKey] ?? [];...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira","depth":4,"bounds":{"left":0.0,"top":0.0518755,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.06304868,"width":0.10106383,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app","depth":4,"bounds":{"left":0.0,"top":0.08459697,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app","depth":5,"bounds":{"left":0.013297873,"top":0.09577015,"width":0.18816489,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app","depth":4,"bounds":{"left":0.0,"top":0.11731844,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app","depth":5,"bounds":{"left":0.013297873,"top":0.12849163,"width":0.15674867,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.06732048,"top":0.1245012,"width":0.007978723,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New Tab","depth":4,"bounds":{"left":0.0028257978,"top":0.15163608,"width":0.07413564,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"bounds":{"left":0.0028257978,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Close Google Gemini (⌃X)","depth":6,"bounds":{"left":0.013796543,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Tabs from other devices","depth":6,"bounds":{"left":0.024933511,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"bounds":{"left":0.036070477,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"bounds":{"left":0.04720745,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"AI Chat settings","depth":7,"bounds":{"left":0.35854387,"top":0.055067837,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Close","depth":7,"bounds":{"left":0.37051198,"top":0.055067837,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"WORK, Google Account: lukas.kovalik@jiminny.com","depth":12,"bounds":{"left":0.3678524,"top":0.103751,"width":0.013297873,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Main menu","depth":12,"bounds":{"left":0.08494016,"top":0.103751,"width":0.013297873,"height":0.031923383},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New chat","depth":12,"bounds":{"left":0.09823803,"top":0.10454908,"width":0.028590426,"height":0.030327214},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Gemini","depth":15,"bounds":{"left":0.1008976,"top":0.10973663,"width":0.021941489,"height":0.020351157},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"New Chat","depth":12,"bounds":{"left":0.33992687,"top":0.103751,"width":0.013297873,"height":0.031923383},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Open menu for conversation actions.","depth":12,"bounds":{"left":0.35322472,"top":0.103751,"width":0.013297873,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXHeading","text":"Conversation with Gemini","depth":15,"bounds":{"left":0.079288565,"top":0.14764565,"width":0.0003324468,"height":0.0007980846},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Conversation with Gemini","depth":16,"bounds":{"left":0.079288565,"top":0.15003991,"width":0.1200133,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Show the uploaded image in a lightbox","depth":21,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy prompt","depth":21,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"You said Make a PR of changes Find potential issues and bottlenecks","depth":21,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"You said","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Make a PR of changes Find potential issues and bottlenecks","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Listen","depth":22,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Show thinking","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Gemini said","depth":20,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Gemini said","depth":21,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"I can see you've uploaded a screenshot of a code diff, likely from a version control system given the red and green highlights. I would love to help you review the changes, spot bottlenecks, and help you draft a Pull Request.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"However,","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"the image resolution is far too low for me to read.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"It appears to be a completely zoomed-out view where the code has been reduced to tiny, illegible pixels. Because of this, I cannot extract any text or logic to analyze.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"How You Can Share the Code","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"How You Can Share the Code","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"To help me review your code effectively, please try one of the following:","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Paste the text directly:","depth":26,"bounds":{"left":0.12599733,"top":0.0,"width":0.059175532,"height":0.016360734},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Copy the specific code blocks (both the old and new versions if possible) and paste them directly into our chat.","depth":26,"bounds":{"left":0.12599733,"top":0.0,"width":0.21476063,"height":0.038707104},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Upload the files:","depth":26,"bounds":{"left":0.12599733,"top":0.0,"width":0.042220745,"height":0.016360734},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"If the changes are extensive, you can upload the raw text or code files.","depth":26,"bounds":{"left":0.16821809,"top":0.0,"width":0.17154256,"height":0.016360734},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Take high-resolution screenshots:","depth":26,"bounds":{"left":0.12599733,"top":0.008778931,"width":0.08843085,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"If you must use images, take closer, readable screenshots of the specific functions or methods you want me to review.","depth":26,"bounds":{"left":0.12599733,"top":0.008778931,"width":0.23021941,"height":0.038707104},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Once you provide the readable code, I can dive right in to identify potential bugs, assess performance bottlenecks, and help you summarize the changes for your PR!","depth":24,"bounds":{"left":0.11336436,"top":0.06624102,"width":0.24534574,"height":0.038707104},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Good response","depth":22,"bounds":{"left":0.1100399,"top":0.12290503,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Bad response","depth":22,"bounds":{"left":0.120678194,"top":0.12290503,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Share & export","depth":21,"bounds":{"left":0.13131648,"top":0.12290503,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy","depth":22,"bounds":{"left":0.1419548,"top":0.12290503,"width":0.010638298,"height":0.025538707},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Show more options","depth":21,"bounds":{"left":0.15259309,"top":0.12290503,"width":0.010638298,"height":0.025538707},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy prompt","depth":21,"bounds":{"left":0.17121011,"top":0.18355946,"width":0.013297873,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Edit","depth":21,"bounds":{"left":0.18583776,"top":0.18355946,"width":0.013297873,"height":0.031923383},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"You said app/Component/ES/Listeners/UpdateMultipleTargetsListener.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\\Component\\ES\\Listeners; namespace Jiminny\\Component\\ES\\Listeners; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Contracts\\ES\\Events\\UpdateMultipleEntities; use Jiminny\\Contracts\\ES\\Events\\UpdateMultipleEntities; use Psr\\Log\\LoggerInterface; use Psr\\Log\\LoggerInterface; AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntities(), $event->getEntities(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } } } app/Component/ES/Listeners/UpdateSingleTargetListener.php +9-1Lines changed: 9 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Actions\\TrackElasticSearchOperations; use Jiminny\\Component\\ES\\Actions\\TrackElasticSearchOperations; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder; use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Contracts\\ES\\Events\\UpdateSingleEntity; use Jiminny\\Contracts\\ES\\Events\\UpdateSingleEntity; use Psr\\Log\\LoggerInterface; use Psr\\Log\\LoggerInterface; 'entityId' => $event->getEntityId(), 'entityId' => $event->getEntityId(), ]); ]); /** * @important: * Synchronous event should eventually be deprecated. * Instant write operations are blocking and should be used sparingly. * It is much better in terms of performance to write 100 or 1000 documents at once, * and have one blocking reindex operation, instead of writing 10 documents synchronously. */ if ($event->isSyncEvent()) { if ($event->isSyncEvent()) { $this->handleSyncEvent($event); $this->handleSyncEvent($event); AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntityId(), $event->getEntityId(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } app/Component/ES/Processor/Actions/UpsertDocumentsAction.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Processor\\DTOs\\SimpleCollection; use Jiminny\\Component\\ES\\Processor\\DTOs\\SimpleCollection; use Jiminny\\Component\\ES\\Processor\\ResponseEvaluator; use Jiminny\\Component\\ES\\Processor\\ResponseEvaluator; use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait; use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Exceptions\\InvalidDataException; use Jiminny\\Exceptions\\InvalidDataException; use Sentry\\Laravel\\Facade as Sentry; use Sentry\\Laravel\\Facade as Sentry; AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( entityType: $this->updateTarget, entityType: $this->updateTarget, entityId: (int) $document->getId(), entityId: (int) $document->getId(), withPriority: true priority: QueuePriorityEnum::HIGH, ); ); } } app/Component/ES/Processor/DTOs/SelectionList.php +54-17Lines changed: 54 additions & 17 deletions Original file line numberOriginal file lineDiff line numberDiff line change namespace Jiminny\\Component\\ES\\Processor\\DTOs; namespace Jiminny\\Component\\ES\\Processor\\DTOs; use Jiminny\\Component\\ES\\QueuePriorityEnum; /** /** * A very basic and simple collection of entity IDs. * A very basic and simple collection of entity IDs. */ */ class SelectionList class SelectionList { { public function __construct( private const int DEFAULT_CHUNK = 200; private readonly array $priorityEntityIdList = [], private readonly array $normalEntityIdList = [], private int $chunkSize = self::DEFAULT_CHUNK; private readonly bool $isStaleChunkSelected = false, private bool $isStaleChunkSelected = false; private readonly int $chunkSize = 200, private array $selectedEntityIds = []; ) { // Do nothing public function setChunkSize(int $chunkSize): void { $this->chunkSize = $chunkSize; } } public function getAllIds(): array public function markStale(): void { { return array_merge($this->priorityEntityIdList, $this->normalEntityIdList); $this->isStaleChunkSelected = true; } } public function count(): int public function addEntityList(string|QueuePriorityEnum $priority, array $entityIds): void { { return count($this->priorityEntityIdList) + count($this->normalEntityIdList); $priorityKey = $this->normalisePriority($priority); if (! array_key_exists($priorityKey, $this->selectedEntityIds)) { $this->selectedEntityIds[$priorityKey] = []; } $this->selectedEntityIds[$priorityKey] = array_merge($this->selectedEntityIds[$priorityKey], $entityIds); } } public function isEmpty(): bool /** * @return string[] */ public function getEntityListGroups(): array { { return empty($this->priorityEntityIdList) && empty($this->normalEntityIdList); return array_keys($this->selectedEntityIds); } } public function getHighPriorityEntityIds(): array public function getEntityListItemsByGroup(string|QueuePriorityEnum $priority): array { { return $this->priorityEntityIdList; $priorityKey = $this->normalisePriority($priority); return $this->selectedEntityIds[$priorityKey] ?? []; } } public function getNormalPriorityEntityId(): array public function getAllIds(): array { { return $this->normalEntityIdList; $allIds = []; foreach ($this->selectedEntityIds as $entityIds) { $allIds = array_merge($allIds, $entityIds); } return $allIds; } public function count(): int { return array_sum( array_map('count', $this->selectedEntityIds) ); } public function isEmpty(): bool { return $this->count() === 0; } } public function isStaleChunkSelected(): bool public function isStaleChunkSelected(): bool { { return $this->count() >= $this->chunkSize; return $this->count() >= $this->chunkSize; } } private function normalisePriority(string|QueuePriorityEnum $priority): string { return $priority instanceof QueuePriorityEnum ? $priority->value : $priority; } } } app/Component/ES/Processor/Traits/SelectEntityListTrait.php +27-4Lines changed: 27 additions & 4 deletions Original file line numberOriginal file lineDiff line numberDiff line change use Illuminate\\Support\\Facades\\Log; use Illuminate\\Support\\Facades\\Log; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Exceptions\\InvalidArgumentException; use Jiminny\\Exceptions\\InvalidArgumentException; /** /** * Build the correct source list name for the type of entity and priority * Build the correct source list name for the type of entity and priority */ */ trait SelectEntityListTrait trait SelectEntityListTrait { { /** * Highest priority queue for data requiring near-instant availability. * Very few entities should be added here, only when absolutely necessary. */ private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; /** * Normal priority queue for normal application operations. * Almost all update events should pass through this queue */ private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; protected static function selectTargetList(string $entityType, bool $withPriority = false): string /** { * Nonblocking low priority queue. This queue will be consumed only when there is nothing * with higher priority. * * This queue will be used for operations such as es:reset-async */ private const string ENTITIES_LOW_PRIORITIES_LIST = '%s-for-update-low'; protected static function selectTargetList( string $entityType, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { if (! in_array($entityType, UpdateTarget::allowedTargets())) { if (! in_array($entityType, UpdateTarget::allowedTargets())) { throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); } } if ($withPriority) { if ($priority->isHigh()) { Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); } } if ($priority->isLow()) { return sprintf(self::ENTITIES_LOW_PRIORITIES_LIST, $entityType); } return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); } } } } app/Component/ES/Processor/TargetEntitiesSelector.php +26-21Lines changed: 26 additions & 21 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Processor\\DTOs\\SelectionList; use Jiminny\\Component\\ES\\Processor\\DTOs\\SelectionList; use Jiminny\\Component\\ES\\Processor\\Traits\\ExtractIdsTrait; use Jiminny\\Component\\ES\\Processor\\Traits\\ExtractIdsTrait; use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait; use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait; use Jiminny\\Component\\ES\\QueuePriorityEnum; /** /** * This class supplies a list of entities pending an update. * This class supplies a list of entities pending an update. public function select(): SelectionList public function select(): SelectionList { { $staleWorkEntityIds = $this->getStaleChunk(); $selectionList = new SelectionList(); $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $staleWorkEntityIds = $this->getStaleChunk(); if (count($staleWorkEntityIds) > 0) { if (count($staleWorkEntityIds) > 0) { return new SelectionList( /** priorityEntityIdList: $staleWorkEntityIds, * Stale chunks are treated as high priority isStaleChunkSelected: true, */ chunkSize: ChunkSize::getStaleChunkSize($this->updateTarget), $selectionList->markStale(); ); $selectionList->addEntityList(QueuePriorityEnum::HIGH, $staleWorkEntityIds); $selectionList->setChunkSize(ChunkSize::getStaleChunkSize($this->updateTarget)); return $selectionList; } } $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $selectionList->setChunkSize($mainChunkSize); $priorityEntityIdsList = $this->extractIdsFromSet( $priorityEntityIdsList = $this->extractIds(QueuePriorityEnum::HIGH, $mainChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, true), $selectionList->addEntityList(QueuePriorityEnum::HIGH, $priorityEntityIdsList); $mainChunkSize, ); $normalEntityIdsList = []; $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); if ($normalEntityChunkSize > 0) { if ($normalEntityChunkSize > 0) { $normalEntityIdsList = $this->extractIdsFromSet( $normalEntityIdsList = $this->extractIds(QueuePriorityEnum::NORMAL, $normalEntityChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, false), $selectionList->addEntityList(QueuePriorityEnum::NORMAL, $normalEntityIdsList); $normalEntityChunkSize ); } } return new SelectionList( return $selectionList; priorityEntityIdList: $priorityEntityIdsList, normalEntityIdList: $normalEntityIdsList, chunkSize: $mainChunkSize ); } } private function getStaleChunk(): array private function getStaleChunk(): array return []; return []; } } private function extractIds(QueuePriorityEnum $priority, int $chunkSize): array { return $this->extractIdsFromSet( AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, $priority), $chunkSize ); } } } app/Component/ES/AsyncUpdateElasticSearch.php +17-10Lines changed: 17 additions & 10 deletions Original file line numberOriginal file lineDiff line numberDiff line change * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * and other activity related data * and other activity related data */ */ public static function markEntityForUpdate(string $entityType, int $entityId, bool $withPriority = false): void public static function markEntityForUpdate( { string $entityType, $targetList = self::selectTargetList($entityType, $withPriority); int $entityId, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { $targetList = self::selectTargetList($entityType, $priority); Redis::sadd($targetList, $entityId); Redis::sadd($targetList, $entityId); Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ 'entityType' => $entityType, 'entityType' => $entityType, 'entityId' => $entityId, 'entityId' => $entityId, 'collectionKey' => $targetList, 'collectionKey' => $targetList, 'withPriority' => $withPriority, 'priority' => $priority->value, ]); ]); } } public static function bulkMarkEntitiesForUpdate( public static function bulkMarkEntitiesForUpdate( string $entityType, string $entityType, array $entityIds, array $entityIds, bool $withPriority = false QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { ): void { if (empty($entityIds)) { if (empty($entityIds)) { return; return; } } $targetList = self::selectTargetList($entityType, $withPriority); $targetList = self::selectTargetList($entityType, $priority); Redis::saddarray($targetList, $entityIds); Redis::saddarray($targetList, $entityIds); } } * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Takes priority into consideration. * Takes priority into consideration. */ */ public static function getEntitiesSourceList(string $updateTarget, $priority = false): string public static function getEntitiesSourceList( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { return self::selectTargetList($updateTarget, $priority); return self::selectTargetList($updateTarget, $priority); } } /** /** * Externally called helper methods * Externally called helper methods * - count and flush * - count and flush */ */ public static function getEntitiesListCount(string $updateTarget, $priority = false): int public static function getEntitiesListCount( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): int { $targetList = self::selectTargetList($updateTarget, $priority); $targetList = self::selectTargetList($updateTarget, $priority); return Redis::scard($targetList); return Redis::scard($targetList); app/Component/ES/QueuePriorityEnum.php +40Lines changed: 40 additions & 0 deletions Original file line numberOriginal file lineDiff line numberDiff line change <?php declare(strict_types=1); namespace Jiminny\\Component\\ES; use Jiminny\\Exceptions\\InvalidArgumentException; enum QueuePriorityEnum: string { case HIGH = 'high'; case NORMAL = 'normal'; case LOW = 'low'; public static function tryFromString(string $value): self { if (! self::isValid($value)) { throw new InvalidArgumentException( sprintf('Invalid queue priority \"%s\" selected', $value) ); } return self::tryFrom($value); } public static function isValid(string $value): bool { return self::tryFrom($value) !== null; } public function isLow(): bool { return $this === self::LOW; } public function isHigh(): bool { return $this === self::HIGH; } } app/Component/ES/UpdateProcessManager.php +12-9Lines changed: 12 additions & 9 deletions Original file line numberOriginal file lineDiff line numberDiff line change if ($selectionList->isEmpty()) { if ($selectionList->isEmpty()) { return false; return false; } } /** /** * A stale chunk will always be smaller than a regular chunk. * A stale chunk will always be smaller than a regular chunk. * That doesn't mean there aren't any other scheduled entities for processing * That doesn't mean there aren't any other scheduled entities for processing private function rescheduleThrottledEntities(SelectionList $selectionList): void private function rescheduleThrottledEntities(SelectionList $selectionList): void { { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $groups = $selectionList->getEntityListGroups(); $this->updateTarget, foreach ($groups as $eachGroup) { $selectionList->getNormalPriorityEntityId() $groupEntityIds = $selectionList->getEntityListItemsByGroup($eachGroup); ); if (! empty($groupEntityIds)) { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $this->updateTarget, entityType: $this->updateTarget, $selectionList->getHighPriorityEntityIds(), entityIds: $groupEntityIds, true priority: QueuePriorityEnum::tryFromString($eachGroup) ); ); } } } } } } app/Console/Commands/Elasticsearch/AsyncUpdateEsEntities.php +9-3Lines changed: 9 additions & 3 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Illuminate\\Support\\Str; use Illuminate\\Support\\Str; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Component\\ES\\UpdateProcessManager; use Jiminny\\Component\\ES\\UpdateProcessManager; use Jiminny\\Exceptions\\InvalidArgumentException; use Jiminny\\Exceptions\\InvalidArgumentException; use Jiminny\\Traits\\GracefullyStoppable; use Jiminny\\Traits\\GracefullyStoppable; Redis::set($gaugeLockName, true); Redis::set($gaugeLockName, true); Redis::expire($gaugeLockName, 60); Redis::expire($gaugeLockName, 60); $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::HIGH), ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update', $updateTarget), stat: sprintf('jiminny.%s-for-update', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::NORMAL), ); ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), stat: sprintf('jiminny.%s-for-update-low', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, true), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::LOW), ); ); } } app/Console/Commands/Elasticsearch/ResetAsyncElasticSearchCommand.php +5-1Lines changed: 5 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder; use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder; use Jiminny\\Component\\ES\\Processor\\Traits\\ValidateUpdateTargetTrait; use Jiminny\\Component\\ES\\Processor\\Traits\\ValidateUpdateTargetTrait; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Component\\ES\\Repositories\\EsResetRepositoryInterface; use Jiminny\\Component\\ES\\Repositories\\EsResetRepositoryInterface; use Jiminny\\Exceptions\\InvalidArgumentException; use Jiminny\\Exceptions\\InvalidArgumentException; use Jiminny\\Traits\\GracefullyStoppable; use Jiminny\\Traits\\GracefullyStoppable; private function getRemainingScheduledEntities(bool $printStatus = false): int private function getRemainingScheduledEntities(bool $printStatus = false): int { { $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget, true); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount( $this->updateTarget, QueuePriorityEnum::HIGH ); if ($printStatus) { if ($printStatus) { $this->line( $this->line(","depth":21,"bounds":{"left":0.20578457,"top":0.19313647,"width":0.13696809,"height":0.09577015},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"You said","depth":23,"bounds":{"left":0.079288565,"top":0.19393456,"width":0.019946808,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app/Component/ES/Listeners/UpdateMultipleTargetsListener.php","depth":23,"bounds":{"left":0.20578457,"top":0.19473264,"width":0.084773935,"height":0.035514764},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"+2-1Lines changed: 2 additions & 1 deletion","depth":23,"bounds":{"left":0.20578457,"top":0.25219473,"width":0.10388963,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\\Component\\ES\\Listeners;","depth":23,"bounds":{"left":0.20578457,"top":0.2905028,"width":0.11303192,"height":0.054668795},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"namespace Jiminny\\Component\\ES\\Listeners;","depth":23,"bounds":{"left":0.20578457,"top":0.34796488,"width":0.1100399,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch;","depth":23,"bounds":{"left":0.20578457,"top":0.40542698,"width":0.13380983,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch;","depth":23,"bounds":{"left":0.20578457,"top":0.424581,"width":0.13380983,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\QueuePriorityEnum;","depth":23,"bounds":{"left":0.20578457,"top":0.4820431,"width":0.115359046,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Contracts\\ES\\Events\\UpdateMultipleEntities;","depth":23,"bounds":{"left":0.20578457,"top":0.5011971,"width":0.13597074,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Contracts\\ES\\Events\\UpdateMultipleEntities;","depth":23,"bounds":{"left":0.20578457,"top":0.5203512,"width":0.13597074,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Psr\\Log\\LoggerInterface;","depth":23,"bounds":{"left":0.20578457,"top":0.5395052,"width":0.07047872,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Psr\\Log\\LoggerInterface;","depth":23,"bounds":{"left":0.20578457,"top":0.5586592,"width":0.07047872,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(","depth":23,"bounds":{"left":0.20578457,"top":0.6161213,"width":0.13530585,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(","depth":23,"bounds":{"left":0.20578457,"top":0.63527536,"width":0.13530585,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getUpdateTargetValue(),","depth":23,"bounds":{"left":0.20578457,"top":0.6544294,"width":0.0809508,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getUpdateTargetValue(),","depth":23,"bounds":{"left":0.20578457,"top":0.6735834,"width":0.0809508,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getEntities(),","depth":23,"bounds":{"left":0.20578457,"top":0.6927374,"width":0.052526597,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getEntities(),","depth":23,"bounds":{"left":0.20578457,"top":0.7118915,"width":0.052526597,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->isPriority()","depth":23,"bounds":{"left":0.20578457,"top":0.7310455,"width":0.046708778,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL,","depth":23,"bounds":{"left":0.20578457,"top":0.7501995,"width":0.11702128,"height":0.035514764},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":");","depth":23,"bounds":{"left":0.20578457,"top":0.7885076,"width":0.0033244682,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":");","depth":23,"bounds":{"left":0.20578457,"top":0.8076616,"width":0.0033244682,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"bounds":{"left":0.20578457,"top":0.82681566,"width":0.0019946808,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"bounds":{"left":0.20578457,"top":0.8459697,"width":0.0019946808,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"bounds":{"left":0.20578457,"top":0.8651237,"width":0.0019946808,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"bounds":{"left":0.20578457,"top":0.88427776,"width":0.0019946808,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app/Component/ES/Listeners/UpdateSingleTargetListener.php","depth":23,"bounds":{"left":0.20578457,"top":0.9034318,"width":0.07762633,"height":0.035514764},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"+9-1Lines changed: 9 additions & 1 deletion","depth":23,"bounds":{"left":0.20578457,"top":0.96089387,"width":0.104222074,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Actions\\TrackElasticSearchOperations;","depth":23,"bounds":{"left":0.20578457,"top":0.9992019,"width":0.13480718,"height":0.0007981062},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Actions\\TrackElasticSearchOperations;","depth":23,"bounds":{"left":0.20578457,"top":1.0,"width":0.13480718,"height":-0.07581806},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\QueuePriorityEnum;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Contracts\\ES\\Events\\UpdateSingleEntity;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Contracts\\ES\\Events\\UpdateSingleEntity;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Psr\\Log\\LoggerInterface;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Psr\\Log\\LoggerInterface;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"'entityId' => $event->getEntityId(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"'entityId' => $event->getEntityId(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"]);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"]);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/**","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* @important:","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* Synchronous event should eventually be deprecated.","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* Instant write operations are blocking and should be used sparingly.","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* It is much better in terms of performance to write 100 or 1000 documents at once,","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* and have one blocking reindex operation, instead of writing 10 documents synchronously.","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"*/","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"if ($event->isSyncEvent()) {","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"if ($event->isSyncEvent()) {","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$this->handleSyncEvent($event);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$this->handleSyncEvent($event);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AsyncUpdateElasticSearch::markEntityForUpdate(","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AsyncUpdateElasticSearch::markEntityForUpdate(","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getUpdateTargetValue(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getUpdateTargetValue(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getEntityId(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getEntityId(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->isPriority()","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL,","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":");","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":");","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app/Component/ES/Processor/Actions/UpsertDocumentsAction.php","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"+2-1Lines changed: 2 additions & 1 deletion","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Processor\\DTOs\\SimpleCollection;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\DTOs\\SimpleCollection;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\ResponseEvaluator;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\ResponseEvaluator;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\QueuePriorityEnum;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Exceptions\\InvalidDataException;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Exceptions\\InvalidDataException;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Sentry\\Laravel\\Facade as Sentry;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Sentry\\Laravel\\Facade as Sentry;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AsyncUpdateElasticSearch::markEntityForUpdate(","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AsyncUpdateElasticSearch::markEntityForUpdate(","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"entityType: $this->updateTarget,","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"entityType: $this->updateTarget,","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"entityId: (int) $document->getId(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"entityId: (int) $document->getId(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"withPriority: true","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"priority: QueuePriorityEnum::HIGH,","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":");","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":");","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app/Component/ES/Processor/DTOs/SelectionList.php","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"+54-17Lines changed: 54 additions & 17 deletions","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Original file line numberOriginal file lineDiff line numberDiff line change","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"namespace Jiminny\\Component\\ES\\Processor\\DTOs;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"namespace Jiminny\\Component\\ES\\Processor\\DTOs;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\QueuePriorityEnum;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/**","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/**","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* A very basic and simple collection of entity IDs.","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* A very basic and simple collection of entity IDs.","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"*/","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"*/","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"class SelectionList","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"class SelectionList","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function __construct(","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private const int DEFAULT_CHUNK = 200;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private readonly array $priorityEntityIdList = [],","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private readonly array $normalEntityIdList = [],","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private int $chunkSize = self::DEFAULT_CHUNK;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private readonly bool $isStaleChunkSelected = false,","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private bool $isStaleChunkSelected = false;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private readonly int $chunkSize = 200,","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private array $selectedEntityIds = [];","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":") {","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"// Do nothing","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function setChunkSize(int $chunkSize): void","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$this->chunkSize = $chunkSize;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function getAllIds(): array","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function markStale(): void","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"return array_merge($this->priorityEntityIdList, $this->normalEntityIdList);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$this->isStaleChunkSelected = true;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function count(): int","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function addEntityList(string|QueuePriorityEnum $priority, array $entityIds): void","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"return count($this->priorityEntityIdList) + count($this->normalEntityIdList);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$priorityKey = $this->normalisePriority($priority);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"if (! array_key_exists($priorityKey, $this->selectedEntityIds)) {","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$this->selectedEntityIds[$priorityKey] = [];","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$this->selectedEntityIds[$priorityKey] = array_merge($this->selectedEntityIds[$priorityKey], $entityIds);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function isEmpty(): bool","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/**","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* @return string[]","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"*/","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function getEntityListGroups(): array","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"return empty($this->priorityEntityIdList) && empty($this->normalEntityIdList);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"return array_keys($this->selectedEntityIds);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function getHighPriorityEntityIds(): array","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function getEntityListItemsByGroup(string|QueuePriorityEnum $priority): array","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"return $this->priorityEntityIdList;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$priorityKey = $this->normalisePriority($priority);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"return $this->selectedEntityIds[$priorityKey] ?? [];","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"}]...
|
-8035777445156239076
|
-1144453838252598130
|
visual_change
|
accessibility
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
Close tab
New Tab
Customize sidebar
Close Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
AI Chat settings
Close
WORK, Google Account: [EMAIL]
Main menu
New chat
Gemini
New Chat
Open menu for conversation actions.
Conversation with Gemini
Conversation with Gemini
Show the uploaded image in a lightbox
Copy prompt
You said Make a PR of changes Find potential issues and bottlenecks
You said
Make a PR of changes Find potential issues and bottlenecks
Listen
Show thinking
Gemini said
Gemini said
I can see you've uploaded a screenshot of a code diff, likely from a version control system given the red and green highlights. I would love to help you review the changes, spot bottlenecks, and help you draft a Pull Request.
However,
the image resolution is far too low for me to read.
It appears to be a completely zoomed-out view where the code has been reduced to tiny, illegible pixels. Because of this, I cannot extract any text or logic to analyze.
How You Can Share the Code
How You Can Share the Code
To help me review your code effectively, please try one of the following:
Paste the text directly:
Copy the specific code blocks (both the old and new versions if possible) and paste them directly into our chat.
Upload the files:
If the changes are extensive, you can upload the raw text or code files.
Take high-resolution screenshots:
If you must use images, take closer, readable screenshots of the specific functions or methods you want me to review.
Once you provide the readable code, I can dive right in to identify potential bugs, assess performance bottlenecks, and help you summarize the changes for your PR!
Good response
Bad response
Share & export
Copy
Show more options
Copy prompt
Edit
You said app/Component/ES/Listeners/UpdateMultipleTargetsListener.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\Component\ES\Listeners; namespace Jiminny\Component\ES\Listeners; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Contracts\ES\Events\UpdateMultipleEntities; use Jiminny\Contracts\ES\Events\UpdateMultipleEntities; use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface; AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntities(), $event->getEntities(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } } } app/Component/ES/Listeners/UpdateSingleTargetListener.php +9-1Lines changed: 9 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Actions\TrackElasticSearchOperations; use Jiminny\Component\ES\Actions\TrackElasticSearchOperations; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Contracts\ES\Events\UpdateSingleEntity; use Jiminny\Contracts\ES\Events\UpdateSingleEntity; use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface; 'entityId' => $event->getEntityId(), 'entityId' => $event->getEntityId(), ]); ]); /** * @important: * Synchronous event should eventually be deprecated. * Instant write operations are blocking and should be used sparingly. * It is much better in terms of performance to write 100 or 1000 documents at once, * and have one blocking reindex operation, instead of writing 10 documents synchronously. */ if ($event->isSyncEvent()) { if ($event->isSyncEvent()) { $this->handleSyncEvent($event); $this->handleSyncEvent($event); AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntityId(), $event->getEntityId(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } app/Component/ES/Processor/Actions/UpsertDocumentsAction.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SimpleCollection; use Jiminny\Component\ES\Processor\DTOs\SimpleCollection; use Jiminny\Component\ES\Processor\ResponseEvaluator; use Jiminny\Component\ES\Processor\ResponseEvaluator; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Exceptions\InvalidDataException; use Jiminny\Exceptions\InvalidDataException; use Sentry\Laravel\Facade as Sentry; use Sentry\Laravel\Facade as Sentry; AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( entityType: $this->updateTarget, entityType: $this->updateTarget, entityId: (int) $document->getId(), entityId: (int) $document->getId(), withPriority: true priority: QueuePriorityEnum::HIGH, ); ); } } app/Component/ES/Processor/DTOs/SelectionList.php +54-17Lines changed: 54 additions & 17 deletions Original file line numberOriginal file lineDiff line numberDiff line change namespace Jiminny\Component\ES\Processor\DTOs; namespace Jiminny\Component\ES\Processor\DTOs; use Jiminny\Component\ES\QueuePriorityEnum; /** /** * A very basic and simple collection of entity IDs. * A very basic and simple collection of entity IDs. */ */ class SelectionList class SelectionList { { public function __construct( private const int DEFAULT_CHUNK = 200; private readonly array $priorityEntityIdList = [], private readonly array $normalEntityIdList = [], private int $chunkSize = self::DEFAULT_CHUNK; private readonly bool $isStaleChunkSelected = false, private bool $isStaleChunkSelected = false; private readonly int $chunkSize = 200, private array $selectedEntityIds = []; ) { // Do nothing public function setChunkSize(int $chunkSize): void { $this->chunkSize = $chunkSize; } } public function getAllIds(): array public function markStale(): void { { return array_merge($this->priorityEntityIdList, $this->normalEntityIdList); $this->isStaleChunkSelected = true; } } public function count(): int public function addEntityList(string|QueuePriorityEnum $priority, array $entityIds): void { { return count($this->priorityEntityIdList) + count($this->normalEntityIdList); $priorityKey = $this->normalisePriority($priority); if (! array_key_exists($priorityKey, $this->selectedEntityIds)) { $this->selectedEntityIds[$priorityKey] = []; } $this->selectedEntityIds[$priorityKey] = array_merge($this->selectedEntityIds[$priorityKey], $entityIds); } } public function isEmpty(): bool /** * @return string[] */ public function getEntityListGroups(): array { { return empty($this->priorityEntityIdList) && empty($this->normalEntityIdList); return array_keys($this->selectedEntityIds); } } public function getHighPriorityEntityIds(): array public function getEntityListItemsByGroup(string|QueuePriorityEnum $priority): array { { return $this->priorityEntityIdList; $priorityKey = $this->normalisePriority($priority); return $this->selectedEntityIds[$priorityKey] ?? []; } } public function getNormalPriorityEntityId(): array public function getAllIds(): array { { return $this->normalEntityIdList; $allIds = []; foreach ($this->selectedEntityIds as $entityIds) { $allIds = array_merge($allIds, $entityIds); } return $allIds; } public function count(): int { return array_sum( array_map('count', $this->selectedEntityIds) ); } public function isEmpty(): bool { return $this->count() === 0; } } public function isStaleChunkSelected(): bool public function isStaleChunkSelected(): bool { { return $this->count() >= $this->chunkSize; return $this->count() >= $this->chunkSize; } } private function normalisePriority(string|QueuePriorityEnum $priority): string { return $priority instanceof QueuePriorityEnum ? $priority->value : $priority; } } } app/Component/ES/Processor/Traits/SelectEntityListTrait.php +27-4Lines changed: 27 additions & 4 deletions Original file line numberOriginal file lineDiff line numberDiff line change use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; /** /** * Build the correct source list name for the type of entity and priority * Build the correct source list name for the type of entity and priority */ */ trait SelectEntityListTrait trait SelectEntityListTrait { { /** * Highest priority queue for data requiring near-instant availability. * Very few entities should be added here, only when absolutely necessary. */ private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; /** * Normal priority queue for normal application operations. * Almost all update events should pass through this queue */ private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; protected static function selectTargetList(string $entityType, bool $withPriority = false): string /** { * Nonblocking low priority queue. This queue will be consumed only when there is nothing * with higher priority. * * This queue will be used for operations such as es:reset-async */ private const string ENTITIES_LOW_PRIORITIES_LIST = '%s-for-update-low'; protected static function selectTargetList( string $entityType, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { if (! in_array($entityType, UpdateTarget::allowedTargets())) { if (! in_array($entityType, UpdateTarget::allowedTargets())) { throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); } } if ($withPriority) { if ($priority->isHigh()) { Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); } } if ($priority->isLow()) { return sprintf(self::ENTITIES_LOW_PRIORITIES_LIST, $entityType); } return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); } } } } app/Component/ES/Processor/TargetEntitiesSelector.php +26-21Lines changed: 26 additions & 21 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SelectionList; use Jiminny\Component\ES\Processor\DTOs\SelectionList; use Jiminny\Component\ES\Processor\Traits\ExtractIdsTrait; use Jiminny\Component\ES\Processor\Traits\ExtractIdsTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\QueuePriorityEnum; /** /** * This class supplies a list of entities pending an update. * This class supplies a list of entities pending an update. public function select(): SelectionList public function select(): SelectionList { { $staleWorkEntityIds = $this->getStaleChunk(); $selectionList = new SelectionList(); $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $staleWorkEntityIds = $this->getStaleChunk(); if (count($staleWorkEntityIds) > 0) { if (count($staleWorkEntityIds) > 0) { return new SelectionList( /** priorityEntityIdList: $staleWorkEntityIds, * Stale chunks are treated as high priority isStaleChunkSelected: true, */ chunkSize: ChunkSize::getStaleChunkSize($this->updateTarget), $selectionList->markStale(); ); $selectionList->addEntityList(QueuePriorityEnum::HIGH, $staleWorkEntityIds); $selectionList->setChunkSize(ChunkSize::getStaleChunkSize($this->updateTarget)); return $selectionList; } } $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $selectionList->setChunkSize($mainChunkSize); $priorityEntityIdsList = $this->extractIdsFromSet( $priorityEntityIdsList = $this->extractIds(QueuePriorityEnum::HIGH, $mainChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, true), $selectionList->addEntityList(QueuePriorityEnum::HIGH, $priorityEntityIdsList); $mainChunkSize, ); $normalEntityIdsList = []; $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); if ($normalEntityChunkSize > 0) { if ($normalEntityChunkSize > 0) { $normalEntityIdsList = $this->extractIdsFromSet( $normalEntityIdsList = $this->extractIds(QueuePriorityEnum::NORMAL, $normalEntityChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, false), $selectionList->addEntityList(QueuePriorityEnum::NORMAL, $normalEntityIdsList); $normalEntityChunkSize ); } } return new SelectionList( return $selectionList; priorityEntityIdList: $priorityEntityIdsList, normalEntityIdList: $normalEntityIdsList, chunkSize: $mainChunkSize ); } } private function getStaleChunk(): array private function getStaleChunk(): array return []; return []; } } private function extractIds(QueuePriorityEnum $priority, int $chunkSize): array { return $this->extractIdsFromSet( AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, $priority), $chunkSize ); } } } app/Component/ES/AsyncUpdateElasticSearch.php +17-10Lines changed: 17 additions & 10 deletions Original file line numberOriginal file lineDiff line numberDiff line change * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * and other activity related data * and other activity related data */ */ public static function markEntityForUpdate(string $entityType, int $entityId, bool $withPriority = false): void public static function markEntityForUpdate( { string $entityType, $targetList = self::selectTargetList($entityType, $withPriority); int $entityId, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { $targetList = self::selectTargetList($entityType, $priority); Redis::sadd($targetList, $entityId); Redis::sadd($targetList, $entityId); Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ 'entityType' => $entityType, 'entityType' => $entityType, 'entityId' => $entityId, 'entityId' => $entityId, 'collectionKey' => $targetList, 'collectionKey' => $targetList, 'withPriority' => $withPriority, 'priority' => $priority->value, ]); ]); } } public static function bulkMarkEntitiesForUpdate( public static function bulkMarkEntitiesForUpdate( string $entityType, string $entityType, array $entityIds, array $entityIds, bool $withPriority = false QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { ): void { if (empty($entityIds)) { if (empty($entityIds)) { return; return; } } $targetList = self::selectTargetList($entityType, $withPriority); $targetList = self::selectTargetList($entityType, $priority); Redis::saddarray($targetList, $entityIds); Redis::saddarray($targetList, $entityIds); } } * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Takes priority into consideration. * Takes priority into consideration. */ */ public static function getEntitiesSourceList(string $updateTarget, $priority = false): string public static function getEntitiesSourceList( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { return self::selectTargetList($updateTarget, $priority); return self::selectTargetList($updateTarget, $priority); } } /** /** * Externally called helper methods * Externally called helper methods * - count and flush * - count and flush */ */ public static function getEntitiesListCount(string $updateTarget, $priority = false): int public static function getEntitiesListCount( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): int { $targetList = self::selectTargetList($updateTarget, $priority); $targetList = self::selectTargetList($updateTarget, $priority); return Redis::scard($targetList); return Redis::scard($targetList); app/Component/ES/QueuePriorityEnum.php +40Lines changed: 40 additions & 0 deletions Original file line numberOriginal file lineDiff line numberDiff line change <?php declare(strict_types=1); namespace Jiminny\Component\ES; use Jiminny\Exceptions\InvalidArgumentException; enum QueuePriorityEnum: string { case HIGH = 'high'; case NORMAL = 'normal'; case LOW = 'low'; public static function tryFromString(string $value): self { if (! self::isValid($value)) { throw new InvalidArgumentException( sprintf('Invalid queue priority "%s" selected', $value) ); } return self::tryFrom($value); } public static function isValid(string $value): bool { return self::tryFrom($value) !== null; } public function isLow(): bool { return $this === self::LOW; } public function isHigh(): bool { return $this === self::HIGH; } } app/Component/ES/UpdateProcessManager.php +12-9Lines changed: 12 additions & 9 deletions Original file line numberOriginal file lineDiff line numberDiff line change if ($selectionList->isEmpty()) { if ($selectionList->isEmpty()) { return false; return false; } } /** /** * A stale chunk will always be smaller than a regular chunk. * A stale chunk will always be smaller than a regular chunk. * That doesn't mean there aren't any other scheduled entities for processing * That doesn't mean there aren't any other scheduled entities for processing private function rescheduleThrottledEntities(SelectionList $selectionList): void private function rescheduleThrottledEntities(SelectionList $selectionList): void { { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $groups = $selectionList->getEntityListGroups(); $this->updateTarget, foreach ($groups as $eachGroup) { $selectionList->getNormalPriorityEntityId() $groupEntityIds = $selectionList->getEntityListItemsByGroup($eachGroup); ); if (! empty($groupEntityIds)) { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $this->updateTarget, entityType: $this->updateTarget, $selectionList->getHighPriorityEntityIds(), entityIds: $groupEntityIds, true priority: QueuePriorityEnum::tryFromString($eachGroup) ); ); } } } } } } app/Console/Commands/Elasticsearch/AsyncUpdateEsEntities.php +9-3Lines changed: 9 additions & 3 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Illuminate\Support\Str; use Illuminate\Support\Str; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Component\ES\UpdateProcessManager; use Jiminny\Component\ES\UpdateProcessManager; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Traits\GracefullyStoppable; use Jiminny\Traits\GracefullyStoppable; Redis::set($gaugeLockName, true); Redis::set($gaugeLockName, true); Redis::expire($gaugeLockName, 60); Redis::expire($gaugeLockName, 60); $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::HIGH), ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update', $updateTarget), stat: sprintf('jiminny.%s-for-update', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::NORMAL), ); ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), stat: sprintf('jiminny.%s-for-update-low', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, true), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::LOW), ); ); } } app/Console/Commands/Elasticsearch/ResetAsyncElasticSearchCommand.php +5-1Lines changed: 5 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\Traits\ValidateUpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\ValidateUpdateTargetTrait; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Component\ES\Repositories\EsResetRepositoryInterface; use Jiminny\Component\ES\Repositories\EsResetRepositoryInterface; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Traits\GracefullyStoppable; use Jiminny\Traits\GracefullyStoppable; private function getRemainingScheduledEntities(bool $printStatus = false): int private function getRemainingScheduledEntities(bool $printStatus = false): int { { $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget, true); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount( $this->updateTarget, QueuePriorityEnum::HIGH ); if ($printStatus) { if ($printStatus) { $this->line( $this->line(
You said
app/Component/ES/Listeners/UpdateMultipleTargetsListener.php
+2-1Lines changed: 2 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\Component\ES\Listeners;
namespace Jiminny\Component\ES\Listeners;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\QueuePriorityEnum;
use Jiminny\Contracts\ES\Events\UpdateMultipleEntities;
use Jiminny\Contracts\ES\Events\UpdateMultipleEntities;
use Psr\Log\LoggerInterface;
use Psr\Log\LoggerInterface;
AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(
AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(
$event->getUpdateTargetValue(),
$event->getUpdateTargetValue(),
$event->getEntities(),
$event->getEntities(),
$event->isPriority()
$event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL,
);
);
}
}
}
}
app/Component/ES/Listeners/UpdateSingleTargetListener.php
+9-1Lines changed: 9 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Actions\TrackElasticSearchOperations;
use Jiminny\Component\ES\Actions\TrackElasticSearchOperations;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\Processor\EntityQueryBuilder;
use Jiminny\Component\ES\Processor\EntityQueryBuilder;
use Jiminny\Component\ES\QueuePriorityEnum;
use Jiminny\Contracts\ES\Events\UpdateSingleEntity;
use Jiminny\Contracts\ES\Events\UpdateSingleEntity;
use Psr\Log\LoggerInterface;
use Psr\Log\LoggerInterface;
'entityId' => $event->getEntityId(),
'entityId' => $event->getEntityId(),
]);
]);
/**
* @important:
* Synchronous event should eventually be deprecated.
* Instant write operations are blocking and should be used sparingly.
* It is much better in terms of performance to write 100 or 1000 documents at once,
* and have one blocking reindex operation, instead of writing 10 documents synchronously.
*/
if ($event->isSyncEvent()) {
if ($event->isSyncEvent()) {
$this->handleSyncEvent($event);
$this->handleSyncEvent($event);
AsyncUpdateElasticSearch::markEntityForUpdate(
AsyncUpdateElasticSearch::markEntityForUpdate(
$event->getUpdateTargetValue(),
$event->getUpdateTargetValue(),
$event->getEntityId(),
$event->getEntityId(),
$event->isPriority()
$event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL,
);
);
}
}
app/Component/ES/Processor/Actions/UpsertDocumentsAction.php
+2-1Lines changed: 2 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SimpleCollection;
use Jiminny\Component\ES\Processor\DTOs\SimpleCollection;
use Jiminny\Component\ES\Processor\ResponseEvaluator;
use Jiminny\Component\ES\Processor\ResponseEvaluator;
use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait;
use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait;
use Jiminny\Component\ES\QueuePriorityEnum;
use Jiminny\Exceptions\InvalidDataException;
use Jiminny\Exceptions\InvalidDataException;
use Sentry\Laravel\Facade as Sentry;
use Sentry\Laravel\Facade as Sentry;
AsyncUpdateElasticSearch::markEntityForUpdate(
AsyncUpdateElasticSearch::markEntityForUpdate(
entityType: $this->updateTarget,
entityType: $this->updateTarget,
entityId: (int) $document->getId(),
entityId: (int) $document->getId(),
withPriority: true
priority: QueuePriorityEnum::HIGH,
);
);
}
}
app/Component/ES/Processor/DTOs/SelectionList.php
+54-17Lines changed: 54 additions & 17 deletions
Original file line numberOriginal file lineDiff line numberDiff line change
namespace Jiminny\Component\ES\Processor\DTOs;
namespace Jiminny\Component\ES\Processor\DTOs;
use Jiminny\Component\ES\QueuePriorityEnum;
/**
/**
* A very basic and simple collection of entity IDs.
* A very basic and simple collection of entity IDs.
*/
*/
class SelectionList
class SelectionList
{
{
public function __construct(
private const int DEFAULT_CHUNK = 200;
private readonly array $priorityEntityIdList = [],
private readonly array $normalEntityIdList = [],
private int $chunkSize = self::DEFAULT_CHUNK;
private readonly bool $isStaleChunkSelected = false,
private bool $isStaleChunkSelected = false;
private readonly int $chunkSize = 200,
private array $selectedEntityIds = [];
) {
// Do nothing
public function setChunkSize(int $chunkSize): void
{
$this->chunkSize = $chunkSize;
}
}
public function getAllIds(): array
public function markStale(): void
{
{
return array_merge($this->priorityEntityIdList, $this->normalEntityIdList);
$this->isStaleChunkSelected = true;
}
}
public function count(): int
public function addEntityList(string|QueuePriorityEnum $priority, array $entityIds): void
{
{
return count($this->priorityEntityIdList) + count($this->normalEntityIdList);
$priorityKey = $this->normalisePriority($priority);
if (! array_key_exists($priorityKey, $this->selectedEntityIds)) {
$this->selectedEntityIds[$priorityKey] = [];
}
$this->selectedEntityIds[$priorityKey] = array_merge($this->selectedEntityIds[$priorityKey], $entityIds);
}
}
public function isEmpty(): bool
/**
* @return string[]
*/
public function getEntityListGroups(): array
{
{
return empty($this->priorityEntityIdList) && empty($this->normalEntityIdList);
return array_keys($this->selectedEntityIds);
}
}
public function getHighPriorityEntityIds(): array
public function getEntityListItemsByGroup(string|QueuePriorityEnum $priority): array
{
{
return $this->priorityEntityIdList;
$priorityKey = $this->normalisePriority($priority);
return $this->selectedEntityIds[$priorityKey] ?? [];...
|
55688
|
NULL
|
NULL
|
NULL
|
|
55691
|
1933
|
18
|
2026-05-19T06:40:35.522313+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779172835522_m2.jpg...
|
Firefox
|
JY-20808 low priority indexing queue by Vasil-Jimi JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app — Work...
|
1
|
github.com/jiminny/app/pull/12082/changes#diff-49a github.com/jiminny/app/pull/12082/changes#diff-49a79d99c97caf7fc27ecb1dbacab5a29d871822caa0db0c71e94957c28c87af...
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
Close tab
New Tab
Customize sidebar
Close Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
AI Chat settings
Close
WORK, Google Account: [EMAIL]
Main menu
New chat
Gemini
New Chat
Open menu for conversation actions.
Conversation with Gemini
Conversation with Gemini
Show the uploaded image in a lightbox
Copy prompt
You said Make a PR of changes Find potential issues and bottlenecks
You said
Make a PR of changes Find potential issues and bottlenecks
Listen
Show thinking
Gemini said
Gemini said
I can see you've uploaded a screenshot of a code diff, likely from a version control system given the red and green highlights. I would love to help you review the changes, spot bottlenecks, and help you draft a Pull Request.
However,
the image resolution is far too low for me to read.
It appears to be a completely zoomed-out view where the code has been reduced to tiny, illegible pixels. Because of this, I cannot extract any text or logic to analyze.
How You Can Share the Code
How You Can Share the Code
To help me review your code effectively, please try one of the following:
Paste the text directly:
Copy the specific code blocks (both the old and new versions if possible) and paste them directly into our chat.
Upload the files:
If the changes are extensive, you can upload the raw text or code files.
Take high-resolution screenshots:
If you must use images, take closer, readable screenshots of the specific functions or methods you want me to review.
Once you provide the readable code, I can dive right in to identify potential bugs, assess performance bottlenecks, and help you summarize the changes for your PR!
Good response
Bad response
Share & export
Copy
Show more options
Copy prompt
Edit
You said app/Component/ES/Listeners/UpdateMultipleTargetsListener.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\Component\ES\Listeners; namespace Jiminny\Component\ES\Listeners; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Contracts\ES\Events\UpdateMultipleEntities; use Jiminny\Contracts\ES\Events\UpdateMultipleEntities; use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface; AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntities(), $event->getEntities(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } } } app/Component/ES/Listeners/UpdateSingleTargetListener.php +9-1Lines changed: 9 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Actions\TrackElasticSearchOperations; use Jiminny\Component\ES\Actions\TrackElasticSearchOperations; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Contracts\ES\Events\UpdateSingleEntity; use Jiminny\Contracts\ES\Events\UpdateSingleEntity; use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface; 'entityId' => $event->getEntityId(), 'entityId' => $event->getEntityId(), ]); ]); /** * @important: * Synchronous event should eventually be deprecated. * Instant write operations are blocking and should be used sparingly. * It is much better in terms of performance to write 100 or 1000 documents at once, * and have one blocking reindex operation, instead of writing 10 documents synchronously. */ if ($event->isSyncEvent()) { if ($event->isSyncEvent()) { $this->handleSyncEvent($event); $this->handleSyncEvent($event); AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntityId(), $event->getEntityId(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } app/Component/ES/Processor/Actions/UpsertDocumentsAction.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SimpleCollection; use Jiminny\Component\ES\Processor\DTOs\SimpleCollection; use Jiminny\Component\ES\Processor\ResponseEvaluator; use Jiminny\Component\ES\Processor\ResponseEvaluator; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Exceptions\InvalidDataException; use Jiminny\Exceptions\InvalidDataException; use Sentry\Laravel\Facade as Sentry; use Sentry\Laravel\Facade as Sentry; AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( entityType: $this->updateTarget, entityType: $this->updateTarget, entityId: (int) $document->getId(), entityId: (int) $document->getId(), withPriority: true priority: QueuePriorityEnum::HIGH, ); ); } } app/Component/ES/Processor/DTOs/SelectionList.php +54-17Lines changed: 54 additions & 17 deletions Original file line numberOriginal file lineDiff line numberDiff line change namespace Jiminny\Component\ES\Processor\DTOs; namespace Jiminny\Component\ES\Processor\DTOs; use Jiminny\Component\ES\QueuePriorityEnum; /** /** * A very basic and simple collection of entity IDs. * A very basic and simple collection of entity IDs. */ */ class SelectionList class SelectionList { { public function __construct( private const int DEFAULT_CHUNK = 200; private readonly array $priorityEntityIdList = [], private readonly array $normalEntityIdList = [], private int $chunkSize = self::DEFAULT_CHUNK; private readonly bool $isStaleChunkSelected = false, private bool $isStaleChunkSelected = false; private readonly int $chunkSize = 200, private array $selectedEntityIds = []; ) { // Do nothing public function setChunkSize(int $chunkSize): void { $this->chunkSize = $chunkSize; } } public function getAllIds(): array public function markStale(): void { { return array_merge($this->priorityEntityIdList, $this->normalEntityIdList); $this->isStaleChunkSelected = true; } } public function count(): int public function addEntityList(string|QueuePriorityEnum $priority, array $entityIds): void { { return count($this->priorityEntityIdList) + count($this->normalEntityIdList); $priorityKey = $this->normalisePriority($priority); if (! array_key_exists($priorityKey, $this->selectedEntityIds)) { $this->selectedEntityIds[$priorityKey] = []; } $this->selectedEntityIds[$priorityKey] = array_merge($this->selectedEntityIds[$priorityKey], $entityIds); } } public function isEmpty(): bool /** * @return string[] */ public function getEntityListGroups(): array { { return empty($this->priorityEntityIdList) && empty($this->normalEntityIdList); return array_keys($this->selectedEntityIds); } } public function getHighPriorityEntityIds(): array public function getEntityListItemsByGroup(string|QueuePriorityEnum $priority): array { { return $this->priorityEntityIdList; $priorityKey = $this->normalisePriority($priority); return $this->selectedEntityIds[$priorityKey] ?? []; } } public function getNormalPriorityEntityId(): array public function getAllIds(): array { { return $this->normalEntityIdList; $allIds = []; foreach ($this->selectedEntityIds as $entityIds) { $allIds = array_merge($allIds, $entityIds); } return $allIds; } public function count(): int { return array_sum( array_map('count', $this->selectedEntityIds) ); } public function isEmpty(): bool { return $this->count() === 0; } } public function isStaleChunkSelected(): bool public function isStaleChunkSelected(): bool { { return $this->count() >= $this->chunkSize; return $this->count() >= $this->chunkSize; } } private function normalisePriority(string|QueuePriorityEnum $priority): string { return $priority instanceof QueuePriorityEnum ? $priority->value : $priority; } } } app/Component/ES/Processor/Traits/SelectEntityListTrait.php +27-4Lines changed: 27 additions & 4 deletions Original file line numberOriginal file lineDiff line numberDiff line change use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; /** /** * Build the correct source list name for the type of entity and priority * Build the correct source list name for the type of entity and priority */ */ trait SelectEntityListTrait trait SelectEntityListTrait { { /** * Highest priority queue for data requiring near-instant availability. * Very few entities should be added here, only when absolutely necessary. */ private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; /** * Normal priority queue for normal application operations. * Almost all update events should pass through this queue */ private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; protected static function selectTargetList(string $entityType, bool $withPriority = false): string /** { * Nonblocking low priority queue. This queue will be consumed only when there is nothing * with higher priority. * * This queue will be used for operations such as es:reset-async */ private const string ENTITIES_LOW_PRIORITIES_LIST = '%s-for-update-low'; protected static function selectTargetList( string $entityType, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { if (! in_array($entityType, UpdateTarget::allowedTargets())) { if (! in_array($entityType, UpdateTarget::allowedTargets())) { throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); } } if ($withPriority) { if ($priority->isHigh()) { Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); } } if ($priority->isLow()) { return sprintf(self::ENTITIES_LOW_PRIORITIES_LIST, $entityType); } return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); } } } } app/Component/ES/Processor/TargetEntitiesSelector.php +26-21Lines changed: 26 additions & 21 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SelectionList; use Jiminny\Component\ES\Processor\DTOs\SelectionList; use Jiminny\Component\ES\Processor\Traits\ExtractIdsTrait; use Jiminny\Component\ES\Processor\Traits\ExtractIdsTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\QueuePriorityEnum; /** /** * This class supplies a list of entities pending an update. * This class supplies a list of entities pending an update. public function select(): SelectionList public function select(): SelectionList { { $staleWorkEntityIds = $this->getStaleChunk(); $selectionList = new SelectionList(); $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $staleWorkEntityIds = $this->getStaleChunk(); if (count($staleWorkEntityIds) > 0) { if (count($staleWorkEntityIds) > 0) { return new SelectionList( /** priorityEntityIdList: $staleWorkEntityIds, * Stale chunks are treated as high priority isStaleChunkSelected: true, */ chunkSize: ChunkSize::getStaleChunkSize($this->updateTarget), $selectionList->markStale(); ); $selectionList->addEntityList(QueuePriorityEnum::HIGH, $staleWorkEntityIds); $selectionList->setChunkSize(ChunkSize::getStaleChunkSize($this->updateTarget)); return $selectionList; } } $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $selectionList->setChunkSize($mainChunkSize); $priorityEntityIdsList = $this->extractIdsFromSet( $priorityEntityIdsList = $this->extractIds(QueuePriorityEnum::HIGH, $mainChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, true), $selectionList->addEntityList(QueuePriorityEnum::HIGH, $priorityEntityIdsList); $mainChunkSize, ); $normalEntityIdsList = []; $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); if ($normalEntityChunkSize > 0) { if ($normalEntityChunkSize > 0) { $normalEntityIdsList = $this->extractIdsFromSet( $normalEntityIdsList = $this->extractIds(QueuePriorityEnum::NORMAL, $normalEntityChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, false), $selectionList->addEntityList(QueuePriorityEnum::NORMAL, $normalEntityIdsList); $normalEntityChunkSize ); } } return new SelectionList( return $selectionList; priorityEntityIdList: $priorityEntityIdsList, normalEntityIdList: $normalEntityIdsList, chunkSize: $mainChunkSize ); } } private function getStaleChunk(): array private function getStaleChunk(): array return []; return []; } } private function extractIds(QueuePriorityEnum $priority, int $chunkSize): array { return $this->extractIdsFromSet( AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, $priority), $chunkSize ); } } } app/Component/ES/AsyncUpdateElasticSearch.php +17-10Lines changed: 17 additions & 10 deletions Original file line numberOriginal file lineDiff line numberDiff line change * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * and other activity related data * and other activity related data */ */ public static function markEntityForUpdate(string $entityType, int $entityId, bool $withPriority = false): void public static function markEntityForUpdate( { string $entityType, $targetList = self::selectTargetList($entityType, $withPriority); int $entityId, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { $targetList = self::selectTargetList($entityType, $priority); Redis::sadd($targetList, $entityId); Redis::sadd($targetList, $entityId); Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ 'entityType' => $entityType, 'entityType' => $entityType, 'entityId' => $entityId, 'entityId' => $entityId, 'collectionKey' => $targetList, 'collectionKey' => $targetList, 'withPriority' => $withPriority, 'priority' => $priority->value, ]); ]); } } public static function bulkMarkEntitiesForUpdate( public static function bulkMarkEntitiesForUpdate( string $entityType, string $entityType, array $entityIds, array $entityIds, bool $withPriority = false QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { ): void { if (empty($entityIds)) { if (empty($entityIds)) { return; return; } } $targetList = self::selectTargetList($entityType, $withPriority); $targetList = self::selectTargetList($entityType, $priority); Redis::saddarray($targetList, $entityIds); Redis::saddarray($targetList, $entityIds); } } * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Takes priority into consideration. * Takes priority into consideration. */ */ public static function getEntitiesSourceList(string $updateTarget, $priority = false): string public static function getEntitiesSourceList( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { return self::selectTargetList($updateTarget, $priority); return self::selectTargetList($updateTarget, $priority); } } /** /** * Externally called helper methods * Externally called helper methods * - count and flush * - count and flush */ */ public static function getEntitiesListCount(string $updateTarget, $priority = false): int public static function getEntitiesListCount( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): int { $targetList = self::selectTargetList($updateTarget, $priority); $targetList = self::selectTargetList($updateTarget, $priority); return Redis::scard($targetList); return Redis::scard($targetList); app/Component/ES/QueuePriorityEnum.php +40Lines changed: 40 additions & 0 deletions Original file line numberOriginal file lineDiff line numberDiff line change <?php declare(strict_types=1); namespace Jiminny\Component\ES; use Jiminny\Exceptions\InvalidArgumentException; enum QueuePriorityEnum: string { case HIGH = 'high'; case NORMAL = 'normal'; case LOW = 'low'; public static function tryFromString(string $value): self { if (! self::isValid($value)) { throw new InvalidArgumentException( sprintf('Invalid queue priority "%s" selected', $value) ); } return self::tryFrom($value); } public static function isValid(string $value): bool { return self::tryFrom($value) !== null; } public function isLow(): bool { return $this === self::LOW; } public function isHigh(): bool { return $this === self::HIGH; } } app/Component/ES/UpdateProcessManager.php +12-9Lines changed: 12 additions & 9 deletions Original file line numberOriginal file lineDiff line numberDiff line change if ($selectionList->isEmpty()) { if ($selectionList->isEmpty()) { return false; return false; } } /** /** * A stale chunk will always be smaller than a regular chunk. * A stale chunk will always be smaller than a regular chunk. * That doesn't mean there aren't any other scheduled entities for processing * That doesn't mean there aren't any other scheduled entities for processing private function rescheduleThrottledEntities(SelectionList $selectionList): void private function rescheduleThrottledEntities(SelectionList $selectionList): void { { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $groups = $selectionList->getEntityListGroups(); $this->updateTarget, foreach ($groups as $eachGroup) { $selectionList->getNormalPriorityEntityId() $groupEntityIds = $selectionList->getEntityListItemsByGroup($eachGroup); ); if (! empty($groupEntityIds)) { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $this->updateTarget, entityType: $this->updateTarget, $selectionList->getHighPriorityEntityIds(), entityIds: $groupEntityIds, true priority: QueuePriorityEnum::tryFromString($eachGroup) ); ); } } } } } } app/Console/Commands/Elasticsearch/AsyncUpdateEsEntities.php +9-3Lines changed: 9 additions & 3 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Illuminate\Support\Str; use Illuminate\Support\Str; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Component\ES\UpdateProcessManager; use Jiminny\Component\ES\UpdateProcessManager; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Traits\GracefullyStoppable; use Jiminny\Traits\GracefullyStoppable; Redis::set($gaugeLockName, true); Redis::set($gaugeLockName, true); Redis::expire($gaugeLockName, 60); Redis::expire($gaugeLockName, 60); $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::HIGH), ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update', $updateTarget), stat: sprintf('jiminny.%s-for-update', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::NORMAL), ); ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), stat: sprintf('jiminny.%s-for-update-low', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, true), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::LOW), ); ); } } app/Console/Commands/Elasticsearch/ResetAsyncElasticSearchCommand.php +5-1Lines changed: 5 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\Traits\ValidateUpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\ValidateUpdateTargetTrait; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Component\ES\Repositories\EsResetRepositoryInterface; use Jiminny\Component\ES\Repositories\EsResetRepositoryInterface; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Traits\GracefullyStoppable; use Jiminny\Traits\GracefullyStoppable; private function getRemainingScheduledEntities(bool $printStatus = false): int private function getRemainingScheduledEntities(bool $printStatus = false): int { { $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget, true); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount( $this->updateTarget, QueuePriorityEnum::HIGH ); if ($printStatus) { if ($printStatus) { $this->line( $this->line(
You said
app/Component/ES/Listeners/UpdateMultipleTargetsListener.php
+2-1Lines changed: 2 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\Component\ES\Listeners;
namespace Jiminny\Component\ES\Listeners;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\QueuePriorityEnum;
use Jiminny\Contracts\ES\Events\UpdateMultipleEntities;
use Jiminny\Contracts\ES\Events\UpdateMultipleEntities;
use Psr\Log\LoggerInterface;
use Psr\Log\LoggerInterface;
AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(
AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(
$event->getUpdateTargetValue(),
$event->getUpdateTargetValue(),
$event->getEntities(),
$event->getEntities(),
$event->isPriority()
$event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL,
);
);
}
}
}
}
app/Component/ES/Listeners/UpdateSingleTargetListener.php
+9-1Lines changed: 9 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Actions\TrackElasticSearchOperations;
use Jiminny\Component\ES\Actions\TrackElasticSearchOperations;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\Processor\EntityQueryBuilder;
use Jiminny\Component\ES\Processor\EntityQueryBuilder;
use Jiminny\Component\ES\QueuePriorityEnum;
use Jiminny\Contracts\ES\Events\UpdateSingleEntity;
use Jiminny\Contracts\ES\Events\UpdateSingleEntity;
use Psr\Log\LoggerInterface;
use Psr\Log\LoggerInterface;
'entityId' => $event->getEntityId(),
'entityId' => $event->getEntityId(),
]);
]);
/**
* @important:
* Synchronous event should eventually be deprecated.
* Instant write operations are blocking and should be used sparingly.
* It is much better in terms of performance to write 100 or 1000 documents at once,
* and have one blocking reindex operation, instead of writing 10 documents synchronously.
*/
if ($event->isSyncEvent()) {
if ($event->isSyncEvent()) {
$this->handleSyncEvent($event);
$this->handleSyncEvent($event);
AsyncUpdateElasticSearch::markEntityForUpdate(
AsyncUpdateElasticSearch::markEntityForUpdate(
$event->getUpdateTargetValue(),
$event->getUpdateTargetValue(),
$event->getEntityId(),
$event->getEntityId(),
$event->isPriority()
$event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL,
);
);
}
}
app/Component/ES/Processor/Actions/UpsertDocumentsAction.php
+2-1Lines changed: 2 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SimpleCollection;
use Jiminny\Component\ES\Processor\DTOs\SimpleCollection;
use Jiminny\Component\ES\Processor\ResponseEvaluator;
use Jiminny\Component\ES\Processor\ResponseEvaluator;
use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait;...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira","depth":4,"bounds":{"left":0.0,"top":0.0518755,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.06304868,"width":0.10106383,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app","depth":4,"bounds":{"left":0.0,"top":0.08459697,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app","depth":5,"bounds":{"left":0.013297873,"top":0.09577015,"width":0.18816489,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app","depth":4,"bounds":{"left":0.0,"top":0.11731844,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app","depth":5,"bounds":{"left":0.013297873,"top":0.12849163,"width":0.15674867,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.06732048,"top":0.1245012,"width":0.007978723,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New Tab","depth":4,"bounds":{"left":0.0028257978,"top":0.15163608,"width":0.07413564,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"bounds":{"left":0.0028257978,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Close Google Gemini (⌃X)","depth":6,"bounds":{"left":0.013796543,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Tabs from other devices","depth":6,"bounds":{"left":0.024933511,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"bounds":{"left":0.036070477,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"bounds":{"left":0.04720745,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"AI Chat settings","depth":7,"bounds":{"left":0.35854387,"top":0.055067837,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Close","depth":7,"bounds":{"left":0.37051198,"top":0.055067837,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"WORK, Google Account: lukas.kovalik@jiminny.com","depth":12,"bounds":{"left":0.3678524,"top":0.103751,"width":0.013297873,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Main menu","depth":12,"bounds":{"left":0.08494016,"top":0.103751,"width":0.013297873,"height":0.031923383},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New chat","depth":12,"bounds":{"left":0.09823803,"top":0.10454908,"width":0.028590426,"height":0.030327214},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Gemini","depth":15,"bounds":{"left":0.1008976,"top":0.10973663,"width":0.021941489,"height":0.020351157},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"New Chat","depth":12,"bounds":{"left":0.33992687,"top":0.103751,"width":0.013297873,"height":0.031923383},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Open menu for conversation actions.","depth":12,"bounds":{"left":0.35322472,"top":0.103751,"width":0.013297873,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXHeading","text":"Conversation with Gemini","depth":15,"bounds":{"left":0.079288565,"top":0.14764565,"width":0.0003324468,"height":0.0007980846},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Conversation with Gemini","depth":16,"bounds":{"left":0.079288565,"top":0.15003991,"width":0.1200133,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Show the uploaded image in a lightbox","depth":21,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy prompt","depth":21,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"You said Make a PR of changes Find potential issues and bottlenecks","depth":21,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"You said","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Make a PR of changes Find potential issues and bottlenecks","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Listen","depth":22,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Show thinking","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Gemini said","depth":20,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Gemini said","depth":21,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"I can see you've uploaded a screenshot of a code diff, likely from a version control system given the red and green highlights. I would love to help you review the changes, spot bottlenecks, and help you draft a Pull Request.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"However,","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"the image resolution is far too low for me to read.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"It appears to be a completely zoomed-out view where the code has been reduced to tiny, illegible pixels. Because of this, I cannot extract any text or logic to analyze.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"How You Can Share the Code","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"How You Can Share the Code","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"To help me review your code effectively, please try one of the following:","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Paste the text directly:","depth":26,"bounds":{"left":0.12599733,"top":0.0,"width":0.059175532,"height":0.016360734},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Copy the specific code blocks (both the old and new versions if possible) and paste them directly into our chat.","depth":26,"bounds":{"left":0.12599733,"top":0.0,"width":0.21476063,"height":0.038707104},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Upload the files:","depth":26,"bounds":{"left":0.12599733,"top":0.0,"width":0.042220745,"height":0.016360734},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"If the changes are extensive, you can upload the raw text or code files.","depth":26,"bounds":{"left":0.16821809,"top":0.0,"width":0.17154256,"height":0.016360734},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Take high-resolution screenshots:","depth":26,"bounds":{"left":0.12599733,"top":0.008778931,"width":0.08843085,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"If you must use images, take closer, readable screenshots of the specific functions or methods you want me to review.","depth":26,"bounds":{"left":0.12599733,"top":0.008778931,"width":0.23021941,"height":0.038707104},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Once you provide the readable code, I can dive right in to identify potential bugs, assess performance bottlenecks, and help you summarize the changes for your PR!","depth":24,"bounds":{"left":0.11336436,"top":0.06624102,"width":0.24534574,"height":0.038707104},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Good response","depth":22,"bounds":{"left":0.1100399,"top":0.12290503,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Bad response","depth":22,"bounds":{"left":0.120678194,"top":0.12290503,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Share & export","depth":21,"bounds":{"left":0.13131648,"top":0.12290503,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy","depth":22,"bounds":{"left":0.1419548,"top":0.12290503,"width":0.010638298,"height":0.025538707},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Show more options","depth":21,"bounds":{"left":0.15259309,"top":0.12290503,"width":0.010638298,"height":0.025538707},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy prompt","depth":21,"bounds":{"left":0.17121011,"top":0.18355946,"width":0.013297873,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Edit","depth":21,"bounds":{"left":0.18583776,"top":0.18355946,"width":0.013297873,"height":0.031923383},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"You said app/Component/ES/Listeners/UpdateMultipleTargetsListener.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\\Component\\ES\\Listeners; namespace Jiminny\\Component\\ES\\Listeners; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Contracts\\ES\\Events\\UpdateMultipleEntities; use Jiminny\\Contracts\\ES\\Events\\UpdateMultipleEntities; use Psr\\Log\\LoggerInterface; use Psr\\Log\\LoggerInterface; AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntities(), $event->getEntities(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } } } app/Component/ES/Listeners/UpdateSingleTargetListener.php +9-1Lines changed: 9 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Actions\\TrackElasticSearchOperations; use Jiminny\\Component\\ES\\Actions\\TrackElasticSearchOperations; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder; use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Contracts\\ES\\Events\\UpdateSingleEntity; use Jiminny\\Contracts\\ES\\Events\\UpdateSingleEntity; use Psr\\Log\\LoggerInterface; use Psr\\Log\\LoggerInterface; 'entityId' => $event->getEntityId(), 'entityId' => $event->getEntityId(), ]); ]); /** * @important: * Synchronous event should eventually be deprecated. * Instant write operations are blocking and should be used sparingly. * It is much better in terms of performance to write 100 or 1000 documents at once, * and have one blocking reindex operation, instead of writing 10 documents synchronously. */ if ($event->isSyncEvent()) { if ($event->isSyncEvent()) { $this->handleSyncEvent($event); $this->handleSyncEvent($event); AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntityId(), $event->getEntityId(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } app/Component/ES/Processor/Actions/UpsertDocumentsAction.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Processor\\DTOs\\SimpleCollection; use Jiminny\\Component\\ES\\Processor\\DTOs\\SimpleCollection; use Jiminny\\Component\\ES\\Processor\\ResponseEvaluator; use Jiminny\\Component\\ES\\Processor\\ResponseEvaluator; use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait; use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Exceptions\\InvalidDataException; use Jiminny\\Exceptions\\InvalidDataException; use Sentry\\Laravel\\Facade as Sentry; use Sentry\\Laravel\\Facade as Sentry; AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( entityType: $this->updateTarget, entityType: $this->updateTarget, entityId: (int) $document->getId(), entityId: (int) $document->getId(), withPriority: true priority: QueuePriorityEnum::HIGH, ); ); } } app/Component/ES/Processor/DTOs/SelectionList.php +54-17Lines changed: 54 additions & 17 deletions Original file line numberOriginal file lineDiff line numberDiff line change namespace Jiminny\\Component\\ES\\Processor\\DTOs; namespace Jiminny\\Component\\ES\\Processor\\DTOs; use Jiminny\\Component\\ES\\QueuePriorityEnum; /** /** * A very basic and simple collection of entity IDs. * A very basic and simple collection of entity IDs. */ */ class SelectionList class SelectionList { { public function __construct( private const int DEFAULT_CHUNK = 200; private readonly array $priorityEntityIdList = [], private readonly array $normalEntityIdList = [], private int $chunkSize = self::DEFAULT_CHUNK; private readonly bool $isStaleChunkSelected = false, private bool $isStaleChunkSelected = false; private readonly int $chunkSize = 200, private array $selectedEntityIds = []; ) { // Do nothing public function setChunkSize(int $chunkSize): void { $this->chunkSize = $chunkSize; } } public function getAllIds(): array public function markStale(): void { { return array_merge($this->priorityEntityIdList, $this->normalEntityIdList); $this->isStaleChunkSelected = true; } } public function count(): int public function addEntityList(string|QueuePriorityEnum $priority, array $entityIds): void { { return count($this->priorityEntityIdList) + count($this->normalEntityIdList); $priorityKey = $this->normalisePriority($priority); if (! array_key_exists($priorityKey, $this->selectedEntityIds)) { $this->selectedEntityIds[$priorityKey] = []; } $this->selectedEntityIds[$priorityKey] = array_merge($this->selectedEntityIds[$priorityKey], $entityIds); } } public function isEmpty(): bool /** * @return string[] */ public function getEntityListGroups(): array { { return empty($this->priorityEntityIdList) && empty($this->normalEntityIdList); return array_keys($this->selectedEntityIds); } } public function getHighPriorityEntityIds(): array public function getEntityListItemsByGroup(string|QueuePriorityEnum $priority): array { { return $this->priorityEntityIdList; $priorityKey = $this->normalisePriority($priority); return $this->selectedEntityIds[$priorityKey] ?? []; } } public function getNormalPriorityEntityId(): array public function getAllIds(): array { { return $this->normalEntityIdList; $allIds = []; foreach ($this->selectedEntityIds as $entityIds) { $allIds = array_merge($allIds, $entityIds); } return $allIds; } public function count(): int { return array_sum( array_map('count', $this->selectedEntityIds) ); } public function isEmpty(): bool { return $this->count() === 0; } } public function isStaleChunkSelected(): bool public function isStaleChunkSelected(): bool { { return $this->count() >= $this->chunkSize; return $this->count() >= $this->chunkSize; } } private function normalisePriority(string|QueuePriorityEnum $priority): string { return $priority instanceof QueuePriorityEnum ? $priority->value : $priority; } } } app/Component/ES/Processor/Traits/SelectEntityListTrait.php +27-4Lines changed: 27 additions & 4 deletions Original file line numberOriginal file lineDiff line numberDiff line change use Illuminate\\Support\\Facades\\Log; use Illuminate\\Support\\Facades\\Log; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Exceptions\\InvalidArgumentException; use Jiminny\\Exceptions\\InvalidArgumentException; /** /** * Build the correct source list name for the type of entity and priority * Build the correct source list name for the type of entity and priority */ */ trait SelectEntityListTrait trait SelectEntityListTrait { { /** * Highest priority queue for data requiring near-instant availability. * Very few entities should be added here, only when absolutely necessary. */ private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; /** * Normal priority queue for normal application operations. * Almost all update events should pass through this queue */ private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; protected static function selectTargetList(string $entityType, bool $withPriority = false): string /** { * Nonblocking low priority queue. This queue will be consumed only when there is nothing * with higher priority. * * This queue will be used for operations such as es:reset-async */ private const string ENTITIES_LOW_PRIORITIES_LIST = '%s-for-update-low'; protected static function selectTargetList( string $entityType, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { if (! in_array($entityType, UpdateTarget::allowedTargets())) { if (! in_array($entityType, UpdateTarget::allowedTargets())) { throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); } } if ($withPriority) { if ($priority->isHigh()) { Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); } } if ($priority->isLow()) { return sprintf(self::ENTITIES_LOW_PRIORITIES_LIST, $entityType); } return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); } } } } app/Component/ES/Processor/TargetEntitiesSelector.php +26-21Lines changed: 26 additions & 21 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Processor\\DTOs\\SelectionList; use Jiminny\\Component\\ES\\Processor\\DTOs\\SelectionList; use Jiminny\\Component\\ES\\Processor\\Traits\\ExtractIdsTrait; use Jiminny\\Component\\ES\\Processor\\Traits\\ExtractIdsTrait; use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait; use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait; use Jiminny\\Component\\ES\\QueuePriorityEnum; /** /** * This class supplies a list of entities pending an update. * This class supplies a list of entities pending an update. public function select(): SelectionList public function select(): SelectionList { { $staleWorkEntityIds = $this->getStaleChunk(); $selectionList = new SelectionList(); $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $staleWorkEntityIds = $this->getStaleChunk(); if (count($staleWorkEntityIds) > 0) { if (count($staleWorkEntityIds) > 0) { return new SelectionList( /** priorityEntityIdList: $staleWorkEntityIds, * Stale chunks are treated as high priority isStaleChunkSelected: true, */ chunkSize: ChunkSize::getStaleChunkSize($this->updateTarget), $selectionList->markStale(); ); $selectionList->addEntityList(QueuePriorityEnum::HIGH, $staleWorkEntityIds); $selectionList->setChunkSize(ChunkSize::getStaleChunkSize($this->updateTarget)); return $selectionList; } } $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $selectionList->setChunkSize($mainChunkSize); $priorityEntityIdsList = $this->extractIdsFromSet( $priorityEntityIdsList = $this->extractIds(QueuePriorityEnum::HIGH, $mainChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, true), $selectionList->addEntityList(QueuePriorityEnum::HIGH, $priorityEntityIdsList); $mainChunkSize, ); $normalEntityIdsList = []; $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); if ($normalEntityChunkSize > 0) { if ($normalEntityChunkSize > 0) { $normalEntityIdsList = $this->extractIdsFromSet( $normalEntityIdsList = $this->extractIds(QueuePriorityEnum::NORMAL, $normalEntityChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, false), $selectionList->addEntityList(QueuePriorityEnum::NORMAL, $normalEntityIdsList); $normalEntityChunkSize ); } } return new SelectionList( return $selectionList; priorityEntityIdList: $priorityEntityIdsList, normalEntityIdList: $normalEntityIdsList, chunkSize: $mainChunkSize ); } } private function getStaleChunk(): array private function getStaleChunk(): array return []; return []; } } private function extractIds(QueuePriorityEnum $priority, int $chunkSize): array { return $this->extractIdsFromSet( AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, $priority), $chunkSize ); } } } app/Component/ES/AsyncUpdateElasticSearch.php +17-10Lines changed: 17 additions & 10 deletions Original file line numberOriginal file lineDiff line numberDiff line change * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * and other activity related data * and other activity related data */ */ public static function markEntityForUpdate(string $entityType, int $entityId, bool $withPriority = false): void public static function markEntityForUpdate( { string $entityType, $targetList = self::selectTargetList($entityType, $withPriority); int $entityId, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { $targetList = self::selectTargetList($entityType, $priority); Redis::sadd($targetList, $entityId); Redis::sadd($targetList, $entityId); Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ 'entityType' => $entityType, 'entityType' => $entityType, 'entityId' => $entityId, 'entityId' => $entityId, 'collectionKey' => $targetList, 'collectionKey' => $targetList, 'withPriority' => $withPriority, 'priority' => $priority->value, ]); ]); } } public static function bulkMarkEntitiesForUpdate( public static function bulkMarkEntitiesForUpdate( string $entityType, string $entityType, array $entityIds, array $entityIds, bool $withPriority = false QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { ): void { if (empty($entityIds)) { if (empty($entityIds)) { return; return; } } $targetList = self::selectTargetList($entityType, $withPriority); $targetList = self::selectTargetList($entityType, $priority); Redis::saddarray($targetList, $entityIds); Redis::saddarray($targetList, $entityIds); } } * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Takes priority into consideration. * Takes priority into consideration. */ */ public static function getEntitiesSourceList(string $updateTarget, $priority = false): string public static function getEntitiesSourceList( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { return self::selectTargetList($updateTarget, $priority); return self::selectTargetList($updateTarget, $priority); } } /** /** * Externally called helper methods * Externally called helper methods * - count and flush * - count and flush */ */ public static function getEntitiesListCount(string $updateTarget, $priority = false): int public static function getEntitiesListCount( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): int { $targetList = self::selectTargetList($updateTarget, $priority); $targetList = self::selectTargetList($updateTarget, $priority); return Redis::scard($targetList); return Redis::scard($targetList); app/Component/ES/QueuePriorityEnum.php +40Lines changed: 40 additions & 0 deletions Original file line numberOriginal file lineDiff line numberDiff line change <?php declare(strict_types=1); namespace Jiminny\\Component\\ES; use Jiminny\\Exceptions\\InvalidArgumentException; enum QueuePriorityEnum: string { case HIGH = 'high'; case NORMAL = 'normal'; case LOW = 'low'; public static function tryFromString(string $value): self { if (! self::isValid($value)) { throw new InvalidArgumentException( sprintf('Invalid queue priority \"%s\" selected', $value) ); } return self::tryFrom($value); } public static function isValid(string $value): bool { return self::tryFrom($value) !== null; } public function isLow(): bool { return $this === self::LOW; } public function isHigh(): bool { return $this === self::HIGH; } } app/Component/ES/UpdateProcessManager.php +12-9Lines changed: 12 additions & 9 deletions Original file line numberOriginal file lineDiff line numberDiff line change if ($selectionList->isEmpty()) { if ($selectionList->isEmpty()) { return false; return false; } } /** /** * A stale chunk will always be smaller than a regular chunk. * A stale chunk will always be smaller than a regular chunk. * That doesn't mean there aren't any other scheduled entities for processing * That doesn't mean there aren't any other scheduled entities for processing private function rescheduleThrottledEntities(SelectionList $selectionList): void private function rescheduleThrottledEntities(SelectionList $selectionList): void { { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $groups = $selectionList->getEntityListGroups(); $this->updateTarget, foreach ($groups as $eachGroup) { $selectionList->getNormalPriorityEntityId() $groupEntityIds = $selectionList->getEntityListItemsByGroup($eachGroup); ); if (! empty($groupEntityIds)) { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $this->updateTarget, entityType: $this->updateTarget, $selectionList->getHighPriorityEntityIds(), entityIds: $groupEntityIds, true priority: QueuePriorityEnum::tryFromString($eachGroup) ); ); } } } } } } app/Console/Commands/Elasticsearch/AsyncUpdateEsEntities.php +9-3Lines changed: 9 additions & 3 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Illuminate\\Support\\Str; use Illuminate\\Support\\Str; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Component\\ES\\UpdateProcessManager; use Jiminny\\Component\\ES\\UpdateProcessManager; use Jiminny\\Exceptions\\InvalidArgumentException; use Jiminny\\Exceptions\\InvalidArgumentException; use Jiminny\\Traits\\GracefullyStoppable; use Jiminny\\Traits\\GracefullyStoppable; Redis::set($gaugeLockName, true); Redis::set($gaugeLockName, true); Redis::expire($gaugeLockName, 60); Redis::expire($gaugeLockName, 60); $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::HIGH), ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update', $updateTarget), stat: sprintf('jiminny.%s-for-update', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::NORMAL), ); ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), stat: sprintf('jiminny.%s-for-update-low', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, true), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::LOW), ); ); } } app/Console/Commands/Elasticsearch/ResetAsyncElasticSearchCommand.php +5-1Lines changed: 5 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder; use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder; use Jiminny\\Component\\ES\\Processor\\Traits\\ValidateUpdateTargetTrait; use Jiminny\\Component\\ES\\Processor\\Traits\\ValidateUpdateTargetTrait; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Component\\ES\\Repositories\\EsResetRepositoryInterface; use Jiminny\\Component\\ES\\Repositories\\EsResetRepositoryInterface; use Jiminny\\Exceptions\\InvalidArgumentException; use Jiminny\\Exceptions\\InvalidArgumentException; use Jiminny\\Traits\\GracefullyStoppable; use Jiminny\\Traits\\GracefullyStoppable; private function getRemainingScheduledEntities(bool $printStatus = false): int private function getRemainingScheduledEntities(bool $printStatus = false): int { { $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget, true); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount( $this->updateTarget, QueuePriorityEnum::HIGH ); if ($printStatus) { if ($printStatus) { $this->line( $this->line(","depth":21,"bounds":{"left":0.20578457,"top":0.19313647,"width":0.13696809,"height":0.09577015},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"You said","depth":23,"bounds":{"left":0.079288565,"top":0.19393456,"width":0.019946808,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app/Component/ES/Listeners/UpdateMultipleTargetsListener.php","depth":23,"bounds":{"left":0.20578457,"top":0.19473264,"width":0.084773935,"height":0.035514764},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"+2-1Lines changed: 2 additions & 1 deletion","depth":23,"bounds":{"left":0.20578457,"top":0.25219473,"width":0.10388963,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\\Component\\ES\\Listeners;","depth":23,"bounds":{"left":0.20578457,"top":0.2905028,"width":0.11303192,"height":0.054668795},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"namespace Jiminny\\Component\\ES\\Listeners;","depth":23,"bounds":{"left":0.20578457,"top":0.34796488,"width":0.1100399,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch;","depth":23,"bounds":{"left":0.20578457,"top":0.40542698,"width":0.13380983,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch;","depth":23,"bounds":{"left":0.20578457,"top":0.424581,"width":0.13380983,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\QueuePriorityEnum;","depth":23,"bounds":{"left":0.20578457,"top":0.4820431,"width":0.115359046,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Contracts\\ES\\Events\\UpdateMultipleEntities;","depth":23,"bounds":{"left":0.20578457,"top":0.5011971,"width":0.13597074,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Contracts\\ES\\Events\\UpdateMultipleEntities;","depth":23,"bounds":{"left":0.20578457,"top":0.5203512,"width":0.13597074,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Psr\\Log\\LoggerInterface;","depth":23,"bounds":{"left":0.20578457,"top":0.5395052,"width":0.07047872,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Psr\\Log\\LoggerInterface;","depth":23,"bounds":{"left":0.20578457,"top":0.5586592,"width":0.07047872,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(","depth":23,"bounds":{"left":0.20578457,"top":0.6161213,"width":0.13530585,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(","depth":23,"bounds":{"left":0.20578457,"top":0.63527536,"width":0.13530585,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getUpdateTargetValue(),","depth":23,"bounds":{"left":0.20578457,"top":0.6544294,"width":0.0809508,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getUpdateTargetValue(),","depth":23,"bounds":{"left":0.20578457,"top":0.6735834,"width":0.0809508,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getEntities(),","depth":23,"bounds":{"left":0.20578457,"top":0.6927374,"width":0.052526597,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getEntities(),","depth":23,"bounds":{"left":0.20578457,"top":0.7118915,"width":0.052526597,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->isPriority()","depth":23,"bounds":{"left":0.20578457,"top":0.7310455,"width":0.046708778,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL,","depth":23,"bounds":{"left":0.20578457,"top":0.7501995,"width":0.11702128,"height":0.035514764},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":");","depth":23,"bounds":{"left":0.20578457,"top":0.7885076,"width":0.0033244682,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":");","depth":23,"bounds":{"left":0.20578457,"top":0.8076616,"width":0.0033244682,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"bounds":{"left":0.20578457,"top":0.82681566,"width":0.0019946808,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"bounds":{"left":0.20578457,"top":0.8459697,"width":0.0019946808,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"bounds":{"left":0.20578457,"top":0.8651237,"width":0.0019946808,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"bounds":{"left":0.20578457,"top":0.88427776,"width":0.0019946808,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app/Component/ES/Listeners/UpdateSingleTargetListener.php","depth":23,"bounds":{"left":0.20578457,"top":0.9034318,"width":0.07762633,"height":0.035514764},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"+9-1Lines changed: 9 additions & 1 deletion","depth":23,"bounds":{"left":0.20578457,"top":0.96089387,"width":0.104222074,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Actions\\TrackElasticSearchOperations;","depth":23,"bounds":{"left":0.20578457,"top":0.9992019,"width":0.13480718,"height":0.0007981062},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Actions\\TrackElasticSearchOperations;","depth":23,"bounds":{"left":0.20578457,"top":1.0,"width":0.13480718,"height":-0.07581806},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\QueuePriorityEnum;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Contracts\\ES\\Events\\UpdateSingleEntity;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Contracts\\ES\\Events\\UpdateSingleEntity;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Psr\\Log\\LoggerInterface;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Psr\\Log\\LoggerInterface;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"'entityId' => $event->getEntityId(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"'entityId' => $event->getEntityId(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"]);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"]);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/**","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* @important:","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* Synchronous event should eventually be deprecated.","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* Instant write operations are blocking and should be used sparingly.","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* It is much better in terms of performance to write 100 or 1000 documents at once,","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* and have one blocking reindex operation, instead of writing 10 documents synchronously.","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"*/","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"if ($event->isSyncEvent()) {","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"if ($event->isSyncEvent()) {","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$this->handleSyncEvent($event);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$this->handleSyncEvent($event);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AsyncUpdateElasticSearch::markEntityForUpdate(","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AsyncUpdateElasticSearch::markEntityForUpdate(","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getUpdateTargetValue(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getUpdateTargetValue(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getEntityId(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getEntityId(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->isPriority()","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL,","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":");","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":");","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app/Component/ES/Processor/Actions/UpsertDocumentsAction.php","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"+2-1Lines changed: 2 additions & 1 deletion","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Processor\\DTOs\\SimpleCollection;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\DTOs\\SimpleCollection;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\ResponseEvaluator;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\ResponseEvaluator;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"}]...
|
-5855686975390881151
|
-1127563140626834290
|
click
|
accessibility
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
Close tab
New Tab
Customize sidebar
Close Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
AI Chat settings
Close
WORK, Google Account: [EMAIL]
Main menu
New chat
Gemini
New Chat
Open menu for conversation actions.
Conversation with Gemini
Conversation with Gemini
Show the uploaded image in a lightbox
Copy prompt
You said Make a PR of changes Find potential issues and bottlenecks
You said
Make a PR of changes Find potential issues and bottlenecks
Listen
Show thinking
Gemini said
Gemini said
I can see you've uploaded a screenshot of a code diff, likely from a version control system given the red and green highlights. I would love to help you review the changes, spot bottlenecks, and help you draft a Pull Request.
However,
the image resolution is far too low for me to read.
It appears to be a completely zoomed-out view where the code has been reduced to tiny, illegible pixels. Because of this, I cannot extract any text or logic to analyze.
How You Can Share the Code
How You Can Share the Code
To help me review your code effectively, please try one of the following:
Paste the text directly:
Copy the specific code blocks (both the old and new versions if possible) and paste them directly into our chat.
Upload the files:
If the changes are extensive, you can upload the raw text or code files.
Take high-resolution screenshots:
If you must use images, take closer, readable screenshots of the specific functions or methods you want me to review.
Once you provide the readable code, I can dive right in to identify potential bugs, assess performance bottlenecks, and help you summarize the changes for your PR!
Good response
Bad response
Share & export
Copy
Show more options
Copy prompt
Edit
You said app/Component/ES/Listeners/UpdateMultipleTargetsListener.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\Component\ES\Listeners; namespace Jiminny\Component\ES\Listeners; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Contracts\ES\Events\UpdateMultipleEntities; use Jiminny\Contracts\ES\Events\UpdateMultipleEntities; use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface; AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntities(), $event->getEntities(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } } } app/Component/ES/Listeners/UpdateSingleTargetListener.php +9-1Lines changed: 9 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Actions\TrackElasticSearchOperations; use Jiminny\Component\ES\Actions\TrackElasticSearchOperations; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Contracts\ES\Events\UpdateSingleEntity; use Jiminny\Contracts\ES\Events\UpdateSingleEntity; use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface; 'entityId' => $event->getEntityId(), 'entityId' => $event->getEntityId(), ]); ]); /** * @important: * Synchronous event should eventually be deprecated. * Instant write operations are blocking and should be used sparingly. * It is much better in terms of performance to write 100 or 1000 documents at once, * and have one blocking reindex operation, instead of writing 10 documents synchronously. */ if ($event->isSyncEvent()) { if ($event->isSyncEvent()) { $this->handleSyncEvent($event); $this->handleSyncEvent($event); AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntityId(), $event->getEntityId(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } app/Component/ES/Processor/Actions/UpsertDocumentsAction.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SimpleCollection; use Jiminny\Component\ES\Processor\DTOs\SimpleCollection; use Jiminny\Component\ES\Processor\ResponseEvaluator; use Jiminny\Component\ES\Processor\ResponseEvaluator; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Exceptions\InvalidDataException; use Jiminny\Exceptions\InvalidDataException; use Sentry\Laravel\Facade as Sentry; use Sentry\Laravel\Facade as Sentry; AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( entityType: $this->updateTarget, entityType: $this->updateTarget, entityId: (int) $document->getId(), entityId: (int) $document->getId(), withPriority: true priority: QueuePriorityEnum::HIGH, ); ); } } app/Component/ES/Processor/DTOs/SelectionList.php +54-17Lines changed: 54 additions & 17 deletions Original file line numberOriginal file lineDiff line numberDiff line change namespace Jiminny\Component\ES\Processor\DTOs; namespace Jiminny\Component\ES\Processor\DTOs; use Jiminny\Component\ES\QueuePriorityEnum; /** /** * A very basic and simple collection of entity IDs. * A very basic and simple collection of entity IDs. */ */ class SelectionList class SelectionList { { public function __construct( private const int DEFAULT_CHUNK = 200; private readonly array $priorityEntityIdList = [], private readonly array $normalEntityIdList = [], private int $chunkSize = self::DEFAULT_CHUNK; private readonly bool $isStaleChunkSelected = false, private bool $isStaleChunkSelected = false; private readonly int $chunkSize = 200, private array $selectedEntityIds = []; ) { // Do nothing public function setChunkSize(int $chunkSize): void { $this->chunkSize = $chunkSize; } } public function getAllIds(): array public function markStale(): void { { return array_merge($this->priorityEntityIdList, $this->normalEntityIdList); $this->isStaleChunkSelected = true; } } public function count(): int public function addEntityList(string|QueuePriorityEnum $priority, array $entityIds): void { { return count($this->priorityEntityIdList) + count($this->normalEntityIdList); $priorityKey = $this->normalisePriority($priority); if (! array_key_exists($priorityKey, $this->selectedEntityIds)) { $this->selectedEntityIds[$priorityKey] = []; } $this->selectedEntityIds[$priorityKey] = array_merge($this->selectedEntityIds[$priorityKey], $entityIds); } } public function isEmpty(): bool /** * @return string[] */ public function getEntityListGroups(): array { { return empty($this->priorityEntityIdList) && empty($this->normalEntityIdList); return array_keys($this->selectedEntityIds); } } public function getHighPriorityEntityIds(): array public function getEntityListItemsByGroup(string|QueuePriorityEnum $priority): array { { return $this->priorityEntityIdList; $priorityKey = $this->normalisePriority($priority); return $this->selectedEntityIds[$priorityKey] ?? []; } } public function getNormalPriorityEntityId(): array public function getAllIds(): array { { return $this->normalEntityIdList; $allIds = []; foreach ($this->selectedEntityIds as $entityIds) { $allIds = array_merge($allIds, $entityIds); } return $allIds; } public function count(): int { return array_sum( array_map('count', $this->selectedEntityIds) ); } public function isEmpty(): bool { return $this->count() === 0; } } public function isStaleChunkSelected(): bool public function isStaleChunkSelected(): bool { { return $this->count() >= $this->chunkSize; return $this->count() >= $this->chunkSize; } } private function normalisePriority(string|QueuePriorityEnum $priority): string { return $priority instanceof QueuePriorityEnum ? $priority->value : $priority; } } } app/Component/ES/Processor/Traits/SelectEntityListTrait.php +27-4Lines changed: 27 additions & 4 deletions Original file line numberOriginal file lineDiff line numberDiff line change use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; /** /** * Build the correct source list name for the type of entity and priority * Build the correct source list name for the type of entity and priority */ */ trait SelectEntityListTrait trait SelectEntityListTrait { { /** * Highest priority queue for data requiring near-instant availability. * Very few entities should be added here, only when absolutely necessary. */ private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; /** * Normal priority queue for normal application operations. * Almost all update events should pass through this queue */ private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; protected static function selectTargetList(string $entityType, bool $withPriority = false): string /** { * Nonblocking low priority queue. This queue will be consumed only when there is nothing * with higher priority. * * This queue will be used for operations such as es:reset-async */ private const string ENTITIES_LOW_PRIORITIES_LIST = '%s-for-update-low'; protected static function selectTargetList( string $entityType, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { if (! in_array($entityType, UpdateTarget::allowedTargets())) { if (! in_array($entityType, UpdateTarget::allowedTargets())) { throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); } } if ($withPriority) { if ($priority->isHigh()) { Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); } } if ($priority->isLow()) { return sprintf(self::ENTITIES_LOW_PRIORITIES_LIST, $entityType); } return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); } } } } app/Component/ES/Processor/TargetEntitiesSelector.php +26-21Lines changed: 26 additions & 21 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SelectionList; use Jiminny\Component\ES\Processor\DTOs\SelectionList; use Jiminny\Component\ES\Processor\Traits\ExtractIdsTrait; use Jiminny\Component\ES\Processor\Traits\ExtractIdsTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\QueuePriorityEnum; /** /** * This class supplies a list of entities pending an update. * This class supplies a list of entities pending an update. public function select(): SelectionList public function select(): SelectionList { { $staleWorkEntityIds = $this->getStaleChunk(); $selectionList = new SelectionList(); $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $staleWorkEntityIds = $this->getStaleChunk(); if (count($staleWorkEntityIds) > 0) { if (count($staleWorkEntityIds) > 0) { return new SelectionList( /** priorityEntityIdList: $staleWorkEntityIds, * Stale chunks are treated as high priority isStaleChunkSelected: true, */ chunkSize: ChunkSize::getStaleChunkSize($this->updateTarget), $selectionList->markStale(); ); $selectionList->addEntityList(QueuePriorityEnum::HIGH, $staleWorkEntityIds); $selectionList->setChunkSize(ChunkSize::getStaleChunkSize($this->updateTarget)); return $selectionList; } } $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $selectionList->setChunkSize($mainChunkSize); $priorityEntityIdsList = $this->extractIdsFromSet( $priorityEntityIdsList = $this->extractIds(QueuePriorityEnum::HIGH, $mainChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, true), $selectionList->addEntityList(QueuePriorityEnum::HIGH, $priorityEntityIdsList); $mainChunkSize, ); $normalEntityIdsList = []; $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); if ($normalEntityChunkSize > 0) { if ($normalEntityChunkSize > 0) { $normalEntityIdsList = $this->extractIdsFromSet( $normalEntityIdsList = $this->extractIds(QueuePriorityEnum::NORMAL, $normalEntityChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, false), $selectionList->addEntityList(QueuePriorityEnum::NORMAL, $normalEntityIdsList); $normalEntityChunkSize ); } } return new SelectionList( return $selectionList; priorityEntityIdList: $priorityEntityIdsList, normalEntityIdList: $normalEntityIdsList, chunkSize: $mainChunkSize ); } } private function getStaleChunk(): array private function getStaleChunk(): array return []; return []; } } private function extractIds(QueuePriorityEnum $priority, int $chunkSize): array { return $this->extractIdsFromSet( AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, $priority), $chunkSize ); } } } app/Component/ES/AsyncUpdateElasticSearch.php +17-10Lines changed: 17 additions & 10 deletions Original file line numberOriginal file lineDiff line numberDiff line change * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * and other activity related data * and other activity related data */ */ public static function markEntityForUpdate(string $entityType, int $entityId, bool $withPriority = false): void public static function markEntityForUpdate( { string $entityType, $targetList = self::selectTargetList($entityType, $withPriority); int $entityId, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { $targetList = self::selectTargetList($entityType, $priority); Redis::sadd($targetList, $entityId); Redis::sadd($targetList, $entityId); Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ 'entityType' => $entityType, 'entityType' => $entityType, 'entityId' => $entityId, 'entityId' => $entityId, 'collectionKey' => $targetList, 'collectionKey' => $targetList, 'withPriority' => $withPriority, 'priority' => $priority->value, ]); ]); } } public static function bulkMarkEntitiesForUpdate( public static function bulkMarkEntitiesForUpdate( string $entityType, string $entityType, array $entityIds, array $entityIds, bool $withPriority = false QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { ): void { if (empty($entityIds)) { if (empty($entityIds)) { return; return; } } $targetList = self::selectTargetList($entityType, $withPriority); $targetList = self::selectTargetList($entityType, $priority); Redis::saddarray($targetList, $entityIds); Redis::saddarray($targetList, $entityIds); } } * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Takes priority into consideration. * Takes priority into consideration. */ */ public static function getEntitiesSourceList(string $updateTarget, $priority = false): string public static function getEntitiesSourceList( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { return self::selectTargetList($updateTarget, $priority); return self::selectTargetList($updateTarget, $priority); } } /** /** * Externally called helper methods * Externally called helper methods * - count and flush * - count and flush */ */ public static function getEntitiesListCount(string $updateTarget, $priority = false): int public static function getEntitiesListCount( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): int { $targetList = self::selectTargetList($updateTarget, $priority); $targetList = self::selectTargetList($updateTarget, $priority); return Redis::scard($targetList); return Redis::scard($targetList); app/Component/ES/QueuePriorityEnum.php +40Lines changed: 40 additions & 0 deletions Original file line numberOriginal file lineDiff line numberDiff line change <?php declare(strict_types=1); namespace Jiminny\Component\ES; use Jiminny\Exceptions\InvalidArgumentException; enum QueuePriorityEnum: string { case HIGH = 'high'; case NORMAL = 'normal'; case LOW = 'low'; public static function tryFromString(string $value): self { if (! self::isValid($value)) { throw new InvalidArgumentException( sprintf('Invalid queue priority "%s" selected', $value) ); } return self::tryFrom($value); } public static function isValid(string $value): bool { return self::tryFrom($value) !== null; } public function isLow(): bool { return $this === self::LOW; } public function isHigh(): bool { return $this === self::HIGH; } } app/Component/ES/UpdateProcessManager.php +12-9Lines changed: 12 additions & 9 deletions Original file line numberOriginal file lineDiff line numberDiff line change if ($selectionList->isEmpty()) { if ($selectionList->isEmpty()) { return false; return false; } } /** /** * A stale chunk will always be smaller than a regular chunk. * A stale chunk will always be smaller than a regular chunk. * That doesn't mean there aren't any other scheduled entities for processing * That doesn't mean there aren't any other scheduled entities for processing private function rescheduleThrottledEntities(SelectionList $selectionList): void private function rescheduleThrottledEntities(SelectionList $selectionList): void { { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $groups = $selectionList->getEntityListGroups(); $this->updateTarget, foreach ($groups as $eachGroup) { $selectionList->getNormalPriorityEntityId() $groupEntityIds = $selectionList->getEntityListItemsByGroup($eachGroup); ); if (! empty($groupEntityIds)) { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $this->updateTarget, entityType: $this->updateTarget, $selectionList->getHighPriorityEntityIds(), entityIds: $groupEntityIds, true priority: QueuePriorityEnum::tryFromString($eachGroup) ); ); } } } } } } app/Console/Commands/Elasticsearch/AsyncUpdateEsEntities.php +9-3Lines changed: 9 additions & 3 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Illuminate\Support\Str; use Illuminate\Support\Str; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Component\ES\UpdateProcessManager; use Jiminny\Component\ES\UpdateProcessManager; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Traits\GracefullyStoppable; use Jiminny\Traits\GracefullyStoppable; Redis::set($gaugeLockName, true); Redis::set($gaugeLockName, true); Redis::expire($gaugeLockName, 60); Redis::expire($gaugeLockName, 60); $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::HIGH), ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update', $updateTarget), stat: sprintf('jiminny.%s-for-update', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::NORMAL), ); ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), stat: sprintf('jiminny.%s-for-update-low', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, true), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::LOW), ); ); } } app/Console/Commands/Elasticsearch/ResetAsyncElasticSearchCommand.php +5-1Lines changed: 5 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\Traits\ValidateUpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\ValidateUpdateTargetTrait; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Component\ES\Repositories\EsResetRepositoryInterface; use Jiminny\Component\ES\Repositories\EsResetRepositoryInterface; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Traits\GracefullyStoppable; use Jiminny\Traits\GracefullyStoppable; private function getRemainingScheduledEntities(bool $printStatus = false): int private function getRemainingScheduledEntities(bool $printStatus = false): int { { $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget, true); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount( $this->updateTarget, QueuePriorityEnum::HIGH ); if ($printStatus) { if ($printStatus) { $this->line( $this->line(
You said
app/Component/ES/Listeners/UpdateMultipleTargetsListener.php
+2-1Lines changed: 2 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\Component\ES\Listeners;
namespace Jiminny\Component\ES\Listeners;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\QueuePriorityEnum;
use Jiminny\Contracts\ES\Events\UpdateMultipleEntities;
use Jiminny\Contracts\ES\Events\UpdateMultipleEntities;
use Psr\Log\LoggerInterface;
use Psr\Log\LoggerInterface;
AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(
AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(
$event->getUpdateTargetValue(),
$event->getUpdateTargetValue(),
$event->getEntities(),
$event->getEntities(),
$event->isPriority()
$event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL,
);
);
}
}
}
}
app/Component/ES/Listeners/UpdateSingleTargetListener.php
+9-1Lines changed: 9 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Actions\TrackElasticSearchOperations;
use Jiminny\Component\ES\Actions\TrackElasticSearchOperations;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\Processor\EntityQueryBuilder;
use Jiminny\Component\ES\Processor\EntityQueryBuilder;
use Jiminny\Component\ES\QueuePriorityEnum;
use Jiminny\Contracts\ES\Events\UpdateSingleEntity;
use Jiminny\Contracts\ES\Events\UpdateSingleEntity;
use Psr\Log\LoggerInterface;
use Psr\Log\LoggerInterface;
'entityId' => $event->getEntityId(),
'entityId' => $event->getEntityId(),
]);
]);
/**
* @important:
* Synchronous event should eventually be deprecated.
* Instant write operations are blocking and should be used sparingly.
* It is much better in terms of performance to write 100 or 1000 documents at once,
* and have one blocking reindex operation, instead of writing 10 documents synchronously.
*/
if ($event->isSyncEvent()) {
if ($event->isSyncEvent()) {
$this->handleSyncEvent($event);
$this->handleSyncEvent($event);
AsyncUpdateElasticSearch::markEntityForUpdate(
AsyncUpdateElasticSearch::markEntityForUpdate(
$event->getUpdateTargetValue(),
$event->getUpdateTargetValue(),
$event->getEntityId(),
$event->getEntityId(),
$event->isPriority()
$event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL,
);
);
}
}
app/Component/ES/Processor/Actions/UpsertDocumentsAction.php
+2-1Lines changed: 2 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SimpleCollection;
use Jiminny\Component\ES\Processor\DTOs\SimpleCollection;
use Jiminny\Component\ES\Processor\ResponseEvaluator;
use Jiminny\Component\ES\Processor\ResponseEvaluator;
use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait;...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
55690
|
1932
|
11
|
2026-05-19T06:40:35.522316+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779172835522_m1.jpg...
|
Firefox
|
JY-20808 low priority indexing queue by Vasil-Jimi JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app — Work...
|
1
|
github.com/jiminny/app/pull/12082/changes#diff-49a github.com/jiminny/app/pull/12082/changes#diff-49a79d99c97caf7fc27ecb1dbacab5a29d871822caa0db0c71e94957c28c87af...
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
Close tab
New Tab
Customize sidebar
Close Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
AI Chat settings
Close
WORK, Google Account: [EMAIL]
Main menu
New chat
Gemini
New Chat
Open menu for conversation actions.
Conversation with Gemini
Conversation with Gemini
Show the uploaded image in a lightbox
Copy prompt
You said Make a PR of changes Find potential issues and bottlenecks
You said
Make a PR of changes Find potential issues and bottlenecks
Listen
Show thinking
Gemini said
Gemini said
I can see you've uploaded a screenshot of a code diff, likely from a version control system given the red and green highlights. I would love to help you review the changes, spot bottlenecks, and help you draft a Pull Request.
However,
the image resolution is far too low for me to read.
It appears to be a completely zoomed-out view where the code has been reduced to tiny, illegible pixels. Because of this, I cannot extract any text or logic to analyze.
How You Can Share the Code
How You Can Share the Code
To help me review your code effectively, please try one of the following:
Paste the text directly:
Copy the specific code blocks (both the old and new versions if possible) and paste them directly into our chat.
Upload the files:
If the changes are extensive, you can upload the raw text or code files.
Take high-resolution screenshots:
If you must use images, take closer, readable screenshots of the specific functions or methods you want me to review.
Once you provide the readable code, I can dive right in to identify potential bugs, assess performance bottlenecks, and help you summarize the changes for your PR!
Good response
Bad response
Share & export
Copy
Show more options
Copy prompt
Edit
You said app/Component/ES/Listeners/UpdateMultipleTargetsListener.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\Component\ES\Listeners; namespace Jiminny\Component\ES\Listeners; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Contracts\ES\Events\UpdateMultipleEntities; use Jiminny\Contracts\ES\Events\UpdateMultipleEntities; use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface; AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntities(), $event->getEntities(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } } } app/Component/ES/Listeners/UpdateSingleTargetListener.php +9-1Lines changed: 9 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Actions\TrackElasticSearchOperations; use Jiminny\Component\ES\Actions\TrackElasticSearchOperations; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Contracts\ES\Events\UpdateSingleEntity; use Jiminny\Contracts\ES\Events\UpdateSingleEntity; use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface; 'entityId' => $event->getEntityId(), 'entityId' => $event->getEntityId(), ]); ]); /** * @important: * Synchronous event should eventually be deprecated. * Instant write operations are blocking and should be used sparingly. * It is much better in terms of performance to write 100 or 1000 documents at once, * and have one blocking reindex operation, instead of writing 10 documents synchronously. */ if ($event->isSyncEvent()) { if ($event->isSyncEvent()) { $this->handleSyncEvent($event); $this->handleSyncEvent($event); AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntityId(), $event->getEntityId(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } app/Component/ES/Processor/Actions/UpsertDocumentsAction.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SimpleCollection; use Jiminny\Component\ES\Processor\DTOs\SimpleCollection; use Jiminny\Component\ES\Processor\ResponseEvaluator; use Jiminny\Component\ES\Processor\ResponseEvaluator; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Exceptions\InvalidDataException; use Jiminny\Exceptions\InvalidDataException; use Sentry\Laravel\Facade as Sentry; use Sentry\Laravel\Facade as Sentry; AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( entityType: $this->updateTarget, entityType: $this->updateTarget, entityId: (int) $document->getId(), entityId: (int) $document->getId(), withPriority: true priority: QueuePriorityEnum::HIGH, ); ); } } app/Component/ES/Processor/DTOs/SelectionList.php +54-17Lines changed: 54 additions & 17 deletions Original file line numberOriginal file lineDiff line numberDiff line change namespace Jiminny\Component\ES\Processor\DTOs; namespace Jiminny\Component\ES\Processor\DTOs; use Jiminny\Component\ES\QueuePriorityEnum; /** /** * A very basic and simple collection of entity IDs. * A very basic and simple collection of entity IDs. */ */ class SelectionList class SelectionList { { public function __construct( private const int DEFAULT_CHUNK = 200; private readonly array $priorityEntityIdList = [], private readonly array $normalEntityIdList = [], private int $chunkSize = self::DEFAULT_CHUNK; private readonly bool $isStaleChunkSelected = false, private bool $isStaleChunkSelected = false; private readonly int $chunkSize = 200, private array $selectedEntityIds = []; ) { // Do nothing public function setChunkSize(int $chunkSize): void { $this->chunkSize = $chunkSize; } } public function getAllIds(): array public function markStale(): void { { return array_merge($this->priorityEntityIdList, $this->normalEntityIdList); $this->isStaleChunkSelected = true; } } public function count(): int public function addEntityList(string|QueuePriorityEnum $priority, array $entityIds): void { { return count($this->priorityEntityIdList) + count($this->normalEntityIdList); $priorityKey = $this->normalisePriority($priority); if (! array_key_exists($priorityKey, $this->selectedEntityIds)) { $this->selectedEntityIds[$priorityKey] = []; } $this->selectedEntityIds[$priorityKey] = array_merge($this->selectedEntityIds[$priorityKey], $entityIds); } } public function isEmpty(): bool /** * @return string[] */ public function getEntityListGroups(): array { { return empty($this->priorityEntityIdList) && empty($this->normalEntityIdList); return array_keys($this->selectedEntityIds); } } public function getHighPriorityEntityIds(): array public function getEntityListItemsByGroup(string|QueuePriorityEnum $priority): array { { return $this->priorityEntityIdList; $priorityKey = $this->normalisePriority($priority); return $this->selectedEntityIds[$priorityKey] ?? []; } } public function getNormalPriorityEntityId(): array public function getAllIds(): array { { return $this->normalEntityIdList; $allIds = []; foreach ($this->selectedEntityIds as $entityIds) { $allIds = array_merge($allIds, $entityIds); } return $allIds; } public function count(): int { return array_sum( array_map('count', $this->selectedEntityIds) ); } public function isEmpty(): bool { return $this->count() === 0; } } public function isStaleChunkSelected(): bool public function isStaleChunkSelected(): bool { { return $this->count() >= $this->chunkSize; return $this->count() >= $this->chunkSize; } } private function normalisePriority(string|QueuePriorityEnum $priority): string { return $priority instanceof QueuePriorityEnum ? $priority->value : $priority; } } } app/Component/ES/Processor/Traits/SelectEntityListTrait.php +27-4Lines changed: 27 additions & 4 deletions Original file line numberOriginal file lineDiff line numberDiff line change use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; /** /** * Build the correct source list name for the type of entity and priority * Build the correct source list name for the type of entity and priority */ */ trait SelectEntityListTrait trait SelectEntityListTrait { { /** * Highest priority queue for data requiring near-instant availability. * Very few entities should be added here, only when absolutely necessary. */ private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; /** * Normal priority queue for normal application operations. * Almost all update events should pass through this queue */ private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; protected static function selectTargetList(string $entityType, bool $withPriority = false): string /** { * Nonblocking low priority queue. This queue will be consumed only when there is nothing * with higher priority. * * This queue will be used for operations such as es:reset-async */ private const string ENTITIES_LOW_PRIORITIES_LIST = '%s-for-update-low'; protected static function selectTargetList( string $entityType, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { if (! in_array($entityType, UpdateTarget::allowedTargets())) { if (! in_array($entityType, UpdateTarget::allowedTargets())) { throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); } } if ($withPriority) { if ($priority->isHigh()) { Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); } } if ($priority->isLow()) { return sprintf(self::ENTITIES_LOW_PRIORITIES_LIST, $entityType); } return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); } } } } app/Component/ES/Processor/TargetEntitiesSelector.php +26-21Lines changed: 26 additions & 21 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SelectionList; use Jiminny\Component\ES\Processor\DTOs\SelectionList; use Jiminny\Component\ES\Processor\Traits\ExtractIdsTrait; use Jiminny\Component\ES\Processor\Traits\ExtractIdsTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\QueuePriorityEnum; /** /** * This class supplies a list of entities pending an update. * This class supplies a list of entities pending an update. public function select(): SelectionList public function select(): SelectionList { { $staleWorkEntityIds = $this->getStaleChunk(); $selectionList = new SelectionList(); $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $staleWorkEntityIds = $this->getStaleChunk(); if (count($staleWorkEntityIds) > 0) { if (count($staleWorkEntityIds) > 0) { return new SelectionList( /** priorityEntityIdList: $staleWorkEntityIds, * Stale chunks are treated as high priority isStaleChunkSelected: true, */ chunkSize: ChunkSize::getStaleChunkSize($this->updateTarget), $selectionList->markStale(); ); $selectionList->addEntityList(QueuePriorityEnum::HIGH, $staleWorkEntityIds); $selectionList->setChunkSize(ChunkSize::getStaleChunkSize($this->updateTarget)); return $selectionList; } } $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $selectionList->setChunkSize($mainChunkSize); $priorityEntityIdsList = $this->extractIdsFromSet( $priorityEntityIdsList = $this->extractIds(QueuePriorityEnum::HIGH, $mainChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, true), $selectionList->addEntityList(QueuePriorityEnum::HIGH, $priorityEntityIdsList); $mainChunkSize, ); $normalEntityIdsList = []; $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); if ($normalEntityChunkSize > 0) { if ($normalEntityChunkSize > 0) { $normalEntityIdsList = $this->extractIdsFromSet( $normalEntityIdsList = $this->extractIds(QueuePriorityEnum::NORMAL, $normalEntityChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, false), $selectionList->addEntityList(QueuePriorityEnum::NORMAL, $normalEntityIdsList); $normalEntityChunkSize ); } } return new SelectionList( return $selectionList; priorityEntityIdList: $priorityEntityIdsList, normalEntityIdList: $normalEntityIdsList, chunkSize: $mainChunkSize ); } } private function getStaleChunk(): array private function getStaleChunk(): array return []; return []; } } private function extractIds(QueuePriorityEnum $priority, int $chunkSize): array { return $this->extractIdsFromSet( AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, $priority), $chunkSize ); } } } app/Component/ES/AsyncUpdateElasticSearch.php +17-10Lines changed: 17 additions & 10 deletions Original file line numberOriginal file lineDiff line numberDiff line change * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * and other activity related data * and other activity related data */ */ public static function markEntityForUpdate(string $entityType, int $entityId, bool $withPriority = false): void public static function markEntityForUpdate( { string $entityType, $targetList = self::selectTargetList($entityType, $withPriority); int $entityId, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { $targetList = self::selectTargetList($entityType, $priority); Redis::sadd($targetList, $entityId); Redis::sadd($targetList, $entityId); Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ 'entityType' => $entityType, 'entityType' => $entityType, 'entityId' => $entityId, 'entityId' => $entityId, 'collectionKey' => $targetList, 'collectionKey' => $targetList, 'withPriority' => $withPriority, 'priority' => $priority->value, ]); ]); } } public static function bulkMarkEntitiesForUpdate( public static function bulkMarkEntitiesForUpdate( string $entityType, string $entityType, array $entityIds, array $entityIds, bool $withPriority = false QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { ): void { if (empty($entityIds)) { if (empty($entityIds)) { return; return; } } $targetList = self::selectTargetList($entityType, $withPriority); $targetList = self::selectTargetList($entityType, $priority); Redis::saddarray($targetList, $entityIds); Redis::saddarray($targetList, $entityIds); } } * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Takes priority into consideration. * Takes priority into consideration. */ */ public static function getEntitiesSourceList(string $updateTarget, $priority = false): string public static function getEntitiesSourceList( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { return self::selectTargetList($updateTarget, $priority); return self::selectTargetList($updateTarget, $priority); } } /** /** * Externally called helper methods * Externally called helper methods * - count and flush * - count and flush */ */ public static function getEntitiesListCount(string $updateTarget, $priority = false): int public static function getEntitiesListCount( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): int { $targetList = self::selectTargetList($updateTarget, $priority); $targetList = self::selectTargetList($updateTarget, $priority); return Redis::scard($targetList); return Redis::scard($targetList); app/Component/ES/QueuePriorityEnum.php +40Lines changed: 40 additions & 0 deletions Original file line numberOriginal file lineDiff line numberDiff line change <?php declare(strict_types=1); namespace Jiminny\Component\ES; use Jiminny\Exceptions\InvalidArgumentException; enum QueuePriorityEnum: string { case HIGH = 'high'; case NORMAL = 'normal'; case LOW = 'low'; public static function tryFromString(string $value): self { if (! self::isValid($value)) { throw new InvalidArgumentException( sprintf('Invalid queue priority "%s" selected', $value) ); } return self::tryFrom($value); } public static function isValid(string $value): bool { return self::tryFrom($value) !== null; } public function isLow(): bool { return $this === self::LOW; } public function isHigh(): bool { return $this === self::HIGH; } } app/Component/ES/UpdateProcessManager.php +12-9Lines changed: 12 additions & 9 deletions Original file line numberOriginal file lineDiff line numberDiff line change if ($selectionList->isEmpty()) { if ($selectionList->isEmpty()) { return false; return false; } } /** /** * A stale chunk will always be smaller than a regular chunk. * A stale chunk will always be smaller than a regular chunk. * That doesn't mean there aren't any other scheduled entities for processing * That doesn't mean there aren't any other scheduled entities for processing private function rescheduleThrottledEntities(SelectionList $selectionList): void private function rescheduleThrottledEntities(SelectionList $selectionList): void { { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $groups = $selectionList->getEntityListGroups(); $this->updateTarget, foreach ($groups as $eachGroup) { $selectionList->getNormalPriorityEntityId() $groupEntityIds = $selectionList->getEntityListItemsByGroup($eachGroup); ); if (! empty($groupEntityIds)) { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $this->updateTarget, entityType: $this->updateTarget, $selectionList->getHighPriorityEntityIds(), entityIds: $groupEntityIds, true priority: QueuePriorityEnum::tryFromString($eachGroup) ); ); } } } } } } app/Console/Commands/Elasticsearch/AsyncUpdateEsEntities.php +9-3Lines changed: 9 additions & 3 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Illuminate\Support\Str; use Illuminate\Support\Str; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Component\ES\UpdateProcessManager; use Jiminny\Component\ES\UpdateProcessManager; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Traits\GracefullyStoppable; use Jiminny\Traits\GracefullyStoppable; Redis::set($gaugeLockName, true); Redis::set($gaugeLockName, true); Redis::expire($gaugeLockName, 60); Redis::expire($gaugeLockName, 60); $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::HIGH), ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update', $updateTarget), stat: sprintf('jiminny.%s-for-update', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::NORMAL), ); ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), stat: sprintf('jiminny.%s-for-update-low', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, true), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::LOW), ); ); } } app/Console/Commands/Elasticsearch/ResetAsyncElasticSearchCommand.php +5-1Lines changed: 5 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\Traits\ValidateUpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\ValidateUpdateTargetTrait; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Component\ES\Repositories\EsResetRepositoryInterface; use Jiminny\Component\ES\Repositories\EsResetRepositoryInterface; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Traits\GracefullyStoppable; use Jiminny\Traits\GracefullyStoppable; private function getRemainingScheduledEntities(bool $printStatus = false): int private function getRemainingScheduledEntities(bool $printStatus = false): int { { $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget, true); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount( $this->updateTarget, QueuePriorityEnum::HIGH ); if ($printStatus) { if ($printStatus) { $this->line( $this->line(
You said
app/Component/ES/Listeners/UpdateMultipleTargetsListener.php
+2-1Lines changed: 2 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\Component\ES\Listeners;
namespace Jiminny\Component\ES\Listeners;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\QueuePriorityEnum;
use Jiminny\Contracts\ES\Events\UpdateMultipleEntities;
use Jiminny\Contracts\ES\Events\UpdateMultipleEntities;
use Psr\Log\LoggerInterface;
use Psr\Log\LoggerInterface;
AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(
AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(
$event->getUpdateTargetValue(),
$event->getUpdateTargetValue(),
$event->getEntities(),
$event->getEntities(),
$event->isPriority()
$event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL,
);
);
}
}
}
}
app/Component/ES/Listeners/UpdateSingleTargetListener.php
+9-1Lines changed: 9 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Actions\TrackElasticSearchOperations;
use Jiminny\Component\ES\Actions\TrackElasticSearchOperations;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\Processor\EntityQueryBuilder;
use Jiminny\Component\ES\Processor\EntityQueryBuilder;
use Jiminny\Component\ES\QueuePriorityEnum;
use Jiminny\Contracts\ES\Events\UpdateSingleEntity;
use Jiminny\Contracts\ES\Events\UpdateSingleEntity;
use Psr\Log\LoggerInterface;
use Psr\Log\LoggerInterface;
'entityId' => $event->getEntityId(),
'entityId' => $event->getEntityId(),
]);
]);
/**
* @important:
* Synchronous event should eventually be deprecated.
* Instant write operations are blocking and should be used sparingly.
* It is much better in terms of performance to write 100 or 1000 documents at once,
* and have one blocking reindex operation, instead of writing 10 documents synchronously.
*/
if ($event->isSyncEvent()) {
if ($event->isSyncEvent()) {
$this->handleSyncEvent($event);
$this->handleSyncEvent($event);
AsyncUpdateElasticSearch::markEntityForUpdate(
AsyncUpdateElasticSearch::markEntityForUpdate(
$event->getUpdateTargetValue(),
$event->getUpdateTargetValue(),
$event->getEntityId(),
$event->getEntityId(),
$event->isPriority()
$event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL,
);
);
}
}
app/Component/ES/Processor/Actions/UpsertDocumentsAction.php
+2-1Lines changed: 2 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SimpleCollection;
use Jiminny\Component\ES\Processor\DTOs\SimpleCollection;
use Jiminny\Component\ES\Processor\ResponseEvaluator;
use Jiminny\Component\ES\Processor\ResponseEvaluator;
use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait;
use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait;
use Jiminny\Component\ES\QueuePriorityEnum;
use Jiminny\Exceptions\InvalidDataException;...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New Tab","depth":4,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Close Google Gemini (⌃X)","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Tabs from other devices","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"AI Chat settings","depth":7,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Close","depth":7,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"WORK, Google Account: lukas.kovalik@jiminny.com","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Main menu","depth":12,"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New chat","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Gemini","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"New Chat","depth":12,"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Open menu for conversation actions.","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXHeading","text":"Conversation with Gemini","depth":15,"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Conversation with Gemini","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Show the uploaded image in a lightbox","depth":21,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy prompt","depth":21,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"You said Make a PR of changes Find potential issues and bottlenecks","depth":21,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"You said","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Make a PR of changes Find potential issues and bottlenecks","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Listen","depth":22,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Show thinking","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Gemini said","depth":20,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Gemini said","depth":21,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"I can see you've uploaded a screenshot of a code diff, likely from a version control system given the red and green highlights. I would love to help you review the changes, spot bottlenecks, and help you draft a Pull Request.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"However,","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"the image resolution is far too low for me to read.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"It appears to be a completely zoomed-out view where the code has been reduced to tiny, illegible pixels. Because of this, I cannot extract any text or logic to analyze.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"How You Can Share the Code","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"How You Can Share the Code","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"To help me review your code effectively, please try one of the following:","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Paste the text directly:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Copy the specific code blocks (both the old and new versions if possible) and paste them directly into our chat.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Upload the files:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"If the changes are extensive, you can upload the raw text or code files.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Take high-resolution screenshots:","depth":26,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"If you must use images, take closer, readable screenshots of the specific functions or methods you want me to review.","depth":26,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Once you provide the readable code, I can dive right in to identify potential bugs, assess performance bottlenecks, and help you summarize the changes for your PR!","depth":24,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Good response","depth":22,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Bad response","depth":22,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Share & export","depth":21,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy","depth":22,"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Show more options","depth":21,"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy prompt","depth":21,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Edit","depth":21,"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"You said app/Component/ES/Listeners/UpdateMultipleTargetsListener.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\\Component\\ES\\Listeners; namespace Jiminny\\Component\\ES\\Listeners; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Contracts\\ES\\Events\\UpdateMultipleEntities; use Jiminny\\Contracts\\ES\\Events\\UpdateMultipleEntities; use Psr\\Log\\LoggerInterface; use Psr\\Log\\LoggerInterface; AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntities(), $event->getEntities(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } } } app/Component/ES/Listeners/UpdateSingleTargetListener.php +9-1Lines changed: 9 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Actions\\TrackElasticSearchOperations; use Jiminny\\Component\\ES\\Actions\\TrackElasticSearchOperations; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder; use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Contracts\\ES\\Events\\UpdateSingleEntity; use Jiminny\\Contracts\\ES\\Events\\UpdateSingleEntity; use Psr\\Log\\LoggerInterface; use Psr\\Log\\LoggerInterface; 'entityId' => $event->getEntityId(), 'entityId' => $event->getEntityId(), ]); ]); /** * @important: * Synchronous event should eventually be deprecated. * Instant write operations are blocking and should be used sparingly. * It is much better in terms of performance to write 100 or 1000 documents at once, * and have one blocking reindex operation, instead of writing 10 documents synchronously. */ if ($event->isSyncEvent()) { if ($event->isSyncEvent()) { $this->handleSyncEvent($event); $this->handleSyncEvent($event); AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntityId(), $event->getEntityId(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } app/Component/ES/Processor/Actions/UpsertDocumentsAction.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Processor\\DTOs\\SimpleCollection; use Jiminny\\Component\\ES\\Processor\\DTOs\\SimpleCollection; use Jiminny\\Component\\ES\\Processor\\ResponseEvaluator; use Jiminny\\Component\\ES\\Processor\\ResponseEvaluator; use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait; use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Exceptions\\InvalidDataException; use Jiminny\\Exceptions\\InvalidDataException; use Sentry\\Laravel\\Facade as Sentry; use Sentry\\Laravel\\Facade as Sentry; AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( entityType: $this->updateTarget, entityType: $this->updateTarget, entityId: (int) $document->getId(), entityId: (int) $document->getId(), withPriority: true priority: QueuePriorityEnum::HIGH, ); ); } } app/Component/ES/Processor/DTOs/SelectionList.php +54-17Lines changed: 54 additions & 17 deletions Original file line numberOriginal file lineDiff line numberDiff line change namespace Jiminny\\Component\\ES\\Processor\\DTOs; namespace Jiminny\\Component\\ES\\Processor\\DTOs; use Jiminny\\Component\\ES\\QueuePriorityEnum; /** /** * A very basic and simple collection of entity IDs. * A very basic and simple collection of entity IDs. */ */ class SelectionList class SelectionList { { public function __construct( private const int DEFAULT_CHUNK = 200; private readonly array $priorityEntityIdList = [], private readonly array $normalEntityIdList = [], private int $chunkSize = self::DEFAULT_CHUNK; private readonly bool $isStaleChunkSelected = false, private bool $isStaleChunkSelected = false; private readonly int $chunkSize = 200, private array $selectedEntityIds = []; ) { // Do nothing public function setChunkSize(int $chunkSize): void { $this->chunkSize = $chunkSize; } } public function getAllIds(): array public function markStale(): void { { return array_merge($this->priorityEntityIdList, $this->normalEntityIdList); $this->isStaleChunkSelected = true; } } public function count(): int public function addEntityList(string|QueuePriorityEnum $priority, array $entityIds): void { { return count($this->priorityEntityIdList) + count($this->normalEntityIdList); $priorityKey = $this->normalisePriority($priority); if (! array_key_exists($priorityKey, $this->selectedEntityIds)) { $this->selectedEntityIds[$priorityKey] = []; } $this->selectedEntityIds[$priorityKey] = array_merge($this->selectedEntityIds[$priorityKey], $entityIds); } } public function isEmpty(): bool /** * @return string[] */ public function getEntityListGroups(): array { { return empty($this->priorityEntityIdList) && empty($this->normalEntityIdList); return array_keys($this->selectedEntityIds); } } public function getHighPriorityEntityIds(): array public function getEntityListItemsByGroup(string|QueuePriorityEnum $priority): array { { return $this->priorityEntityIdList; $priorityKey = $this->normalisePriority($priority); return $this->selectedEntityIds[$priorityKey] ?? []; } } public function getNormalPriorityEntityId(): array public function getAllIds(): array { { return $this->normalEntityIdList; $allIds = []; foreach ($this->selectedEntityIds as $entityIds) { $allIds = array_merge($allIds, $entityIds); } return $allIds; } public function count(): int { return array_sum( array_map('count', $this->selectedEntityIds) ); } public function isEmpty(): bool { return $this->count() === 0; } } public function isStaleChunkSelected(): bool public function isStaleChunkSelected(): bool { { return $this->count() >= $this->chunkSize; return $this->count() >= $this->chunkSize; } } private function normalisePriority(string|QueuePriorityEnum $priority): string { return $priority instanceof QueuePriorityEnum ? $priority->value : $priority; } } } app/Component/ES/Processor/Traits/SelectEntityListTrait.php +27-4Lines changed: 27 additions & 4 deletions Original file line numberOriginal file lineDiff line numberDiff line change use Illuminate\\Support\\Facades\\Log; use Illuminate\\Support\\Facades\\Log; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Exceptions\\InvalidArgumentException; use Jiminny\\Exceptions\\InvalidArgumentException; /** /** * Build the correct source list name for the type of entity and priority * Build the correct source list name for the type of entity and priority */ */ trait SelectEntityListTrait trait SelectEntityListTrait { { /** * Highest priority queue for data requiring near-instant availability. * Very few entities should be added here, only when absolutely necessary. */ private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; /** * Normal priority queue for normal application operations. * Almost all update events should pass through this queue */ private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; protected static function selectTargetList(string $entityType, bool $withPriority = false): string /** { * Nonblocking low priority queue. This queue will be consumed only when there is nothing * with higher priority. * * This queue will be used for operations such as es:reset-async */ private const string ENTITIES_LOW_PRIORITIES_LIST = '%s-for-update-low'; protected static function selectTargetList( string $entityType, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { if (! in_array($entityType, UpdateTarget::allowedTargets())) { if (! in_array($entityType, UpdateTarget::allowedTargets())) { throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); } } if ($withPriority) { if ($priority->isHigh()) { Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); } } if ($priority->isLow()) { return sprintf(self::ENTITIES_LOW_PRIORITIES_LIST, $entityType); } return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); } } } } app/Component/ES/Processor/TargetEntitiesSelector.php +26-21Lines changed: 26 additions & 21 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Processor\\DTOs\\SelectionList; use Jiminny\\Component\\ES\\Processor\\DTOs\\SelectionList; use Jiminny\\Component\\ES\\Processor\\Traits\\ExtractIdsTrait; use Jiminny\\Component\\ES\\Processor\\Traits\\ExtractIdsTrait; use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait; use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait; use Jiminny\\Component\\ES\\QueuePriorityEnum; /** /** * This class supplies a list of entities pending an update. * This class supplies a list of entities pending an update. public function select(): SelectionList public function select(): SelectionList { { $staleWorkEntityIds = $this->getStaleChunk(); $selectionList = new SelectionList(); $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $staleWorkEntityIds = $this->getStaleChunk(); if (count($staleWorkEntityIds) > 0) { if (count($staleWorkEntityIds) > 0) { return new SelectionList( /** priorityEntityIdList: $staleWorkEntityIds, * Stale chunks are treated as high priority isStaleChunkSelected: true, */ chunkSize: ChunkSize::getStaleChunkSize($this->updateTarget), $selectionList->markStale(); ); $selectionList->addEntityList(QueuePriorityEnum::HIGH, $staleWorkEntityIds); $selectionList->setChunkSize(ChunkSize::getStaleChunkSize($this->updateTarget)); return $selectionList; } } $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $selectionList->setChunkSize($mainChunkSize); $priorityEntityIdsList = $this->extractIdsFromSet( $priorityEntityIdsList = $this->extractIds(QueuePriorityEnum::HIGH, $mainChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, true), $selectionList->addEntityList(QueuePriorityEnum::HIGH, $priorityEntityIdsList); $mainChunkSize, ); $normalEntityIdsList = []; $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); if ($normalEntityChunkSize > 0) { if ($normalEntityChunkSize > 0) { $normalEntityIdsList = $this->extractIdsFromSet( $normalEntityIdsList = $this->extractIds(QueuePriorityEnum::NORMAL, $normalEntityChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, false), $selectionList->addEntityList(QueuePriorityEnum::NORMAL, $normalEntityIdsList); $normalEntityChunkSize ); } } return new SelectionList( return $selectionList; priorityEntityIdList: $priorityEntityIdsList, normalEntityIdList: $normalEntityIdsList, chunkSize: $mainChunkSize ); } } private function getStaleChunk(): array private function getStaleChunk(): array return []; return []; } } private function extractIds(QueuePriorityEnum $priority, int $chunkSize): array { return $this->extractIdsFromSet( AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, $priority), $chunkSize ); } } } app/Component/ES/AsyncUpdateElasticSearch.php +17-10Lines changed: 17 additions & 10 deletions Original file line numberOriginal file lineDiff line numberDiff line change * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * and other activity related data * and other activity related data */ */ public static function markEntityForUpdate(string $entityType, int $entityId, bool $withPriority = false): void public static function markEntityForUpdate( { string $entityType, $targetList = self::selectTargetList($entityType, $withPriority); int $entityId, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { $targetList = self::selectTargetList($entityType, $priority); Redis::sadd($targetList, $entityId); Redis::sadd($targetList, $entityId); Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ 'entityType' => $entityType, 'entityType' => $entityType, 'entityId' => $entityId, 'entityId' => $entityId, 'collectionKey' => $targetList, 'collectionKey' => $targetList, 'withPriority' => $withPriority, 'priority' => $priority->value, ]); ]); } } public static function bulkMarkEntitiesForUpdate( public static function bulkMarkEntitiesForUpdate( string $entityType, string $entityType, array $entityIds, array $entityIds, bool $withPriority = false QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { ): void { if (empty($entityIds)) { if (empty($entityIds)) { return; return; } } $targetList = self::selectTargetList($entityType, $withPriority); $targetList = self::selectTargetList($entityType, $priority); Redis::saddarray($targetList, $entityIds); Redis::saddarray($targetList, $entityIds); } } * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Takes priority into consideration. * Takes priority into consideration. */ */ public static function getEntitiesSourceList(string $updateTarget, $priority = false): string public static function getEntitiesSourceList( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { return self::selectTargetList($updateTarget, $priority); return self::selectTargetList($updateTarget, $priority); } } /** /** * Externally called helper methods * Externally called helper methods * - count and flush * - count and flush */ */ public static function getEntitiesListCount(string $updateTarget, $priority = false): int public static function getEntitiesListCount( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): int { $targetList = self::selectTargetList($updateTarget, $priority); $targetList = self::selectTargetList($updateTarget, $priority); return Redis::scard($targetList); return Redis::scard($targetList); app/Component/ES/QueuePriorityEnum.php +40Lines changed: 40 additions & 0 deletions Original file line numberOriginal file lineDiff line numberDiff line change <?php declare(strict_types=1); namespace Jiminny\\Component\\ES; use Jiminny\\Exceptions\\InvalidArgumentException; enum QueuePriorityEnum: string { case HIGH = 'high'; case NORMAL = 'normal'; case LOW = 'low'; public static function tryFromString(string $value): self { if (! self::isValid($value)) { throw new InvalidArgumentException( sprintf('Invalid queue priority \"%s\" selected', $value) ); } return self::tryFrom($value); } public static function isValid(string $value): bool { return self::tryFrom($value) !== null; } public function isLow(): bool { return $this === self::LOW; } public function isHigh(): bool { return $this === self::HIGH; } } app/Component/ES/UpdateProcessManager.php +12-9Lines changed: 12 additions & 9 deletions Original file line numberOriginal file lineDiff line numberDiff line change if ($selectionList->isEmpty()) { if ($selectionList->isEmpty()) { return false; return false; } } /** /** * A stale chunk will always be smaller than a regular chunk. * A stale chunk will always be smaller than a regular chunk. * That doesn't mean there aren't any other scheduled entities for processing * That doesn't mean there aren't any other scheduled entities for processing private function rescheduleThrottledEntities(SelectionList $selectionList): void private function rescheduleThrottledEntities(SelectionList $selectionList): void { { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $groups = $selectionList->getEntityListGroups(); $this->updateTarget, foreach ($groups as $eachGroup) { $selectionList->getNormalPriorityEntityId() $groupEntityIds = $selectionList->getEntityListItemsByGroup($eachGroup); ); if (! empty($groupEntityIds)) { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $this->updateTarget, entityType: $this->updateTarget, $selectionList->getHighPriorityEntityIds(), entityIds: $groupEntityIds, true priority: QueuePriorityEnum::tryFromString($eachGroup) ); ); } } } } } } app/Console/Commands/Elasticsearch/AsyncUpdateEsEntities.php +9-3Lines changed: 9 additions & 3 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Illuminate\\Support\\Str; use Illuminate\\Support\\Str; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Component\\ES\\UpdateProcessManager; use Jiminny\\Component\\ES\\UpdateProcessManager; use Jiminny\\Exceptions\\InvalidArgumentException; use Jiminny\\Exceptions\\InvalidArgumentException; use Jiminny\\Traits\\GracefullyStoppable; use Jiminny\\Traits\\GracefullyStoppable; Redis::set($gaugeLockName, true); Redis::set($gaugeLockName, true); Redis::expire($gaugeLockName, 60); Redis::expire($gaugeLockName, 60); $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::HIGH), ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update', $updateTarget), stat: sprintf('jiminny.%s-for-update', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::NORMAL), ); ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), stat: sprintf('jiminny.%s-for-update-low', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, true), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::LOW), ); ); } } app/Console/Commands/Elasticsearch/ResetAsyncElasticSearchCommand.php +5-1Lines changed: 5 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder; use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder; use Jiminny\\Component\\ES\\Processor\\Traits\\ValidateUpdateTargetTrait; use Jiminny\\Component\\ES\\Processor\\Traits\\ValidateUpdateTargetTrait; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Component\\ES\\Repositories\\EsResetRepositoryInterface; use Jiminny\\Component\\ES\\Repositories\\EsResetRepositoryInterface; use Jiminny\\Exceptions\\InvalidArgumentException; use Jiminny\\Exceptions\\InvalidArgumentException; use Jiminny\\Traits\\GracefullyStoppable; use Jiminny\\Traits\\GracefullyStoppable; private function getRemainingScheduledEntities(bool $printStatus = false): int private function getRemainingScheduledEntities(bool $printStatus = false): int { { $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget, true); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount( $this->updateTarget, QueuePriorityEnum::HIGH ); if ($printStatus) { if ($printStatus) { $this->line( $this->line(","depth":21,"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"You said","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app/Component/ES/Listeners/UpdateMultipleTargetsListener.php","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"+2-1Lines changed: 2 additions & 1 deletion","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\\Component\\ES\\Listeners;","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"namespace Jiminny\\Component\\ES\\Listeners;","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch;","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch;","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\QueuePriorityEnum;","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Contracts\\ES\\Events\\UpdateMultipleEntities;","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Contracts\\ES\\Events\\UpdateMultipleEntities;","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Psr\\Log\\LoggerInterface;","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Psr\\Log\\LoggerInterface;","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getUpdateTargetValue(),","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getUpdateTargetValue(),","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getEntities(),","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getEntities(),","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->isPriority()","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL,","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":");","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":");","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app/Component/ES/Listeners/UpdateSingleTargetListener.php","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"+9-1Lines changed: 9 additions & 1 deletion","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Actions\\TrackElasticSearchOperations;","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Actions\\TrackElasticSearchOperations;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\QueuePriorityEnum;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Contracts\\ES\\Events\\UpdateSingleEntity;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Contracts\\ES\\Events\\UpdateSingleEntity;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Psr\\Log\\LoggerInterface;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Psr\\Log\\LoggerInterface;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"'entityId' => $event->getEntityId(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"'entityId' => $event->getEntityId(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"]);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"]);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/**","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* @important:","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* Synchronous event should eventually be deprecated.","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* Instant write operations are blocking and should be used sparingly.","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* It is much better in terms of performance to write 100 or 1000 documents at once,","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* and have one blocking reindex operation, instead of writing 10 documents synchronously.","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"*/","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"if ($event->isSyncEvent()) {","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"if ($event->isSyncEvent()) {","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$this->handleSyncEvent($event);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$this->handleSyncEvent($event);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AsyncUpdateElasticSearch::markEntityForUpdate(","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AsyncUpdateElasticSearch::markEntityForUpdate(","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getUpdateTargetValue(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getUpdateTargetValue(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getEntityId(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getEntityId(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->isPriority()","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL,","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":");","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":");","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app/Component/ES/Processor/Actions/UpsertDocumentsAction.php","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"+2-1Lines changed: 2 additions & 1 deletion","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Processor\\DTOs\\SimpleCollection;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\DTOs\\SimpleCollection;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\ResponseEvaluator;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\ResponseEvaluator;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\QueuePriorityEnum;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Exceptions\\InvalidDataException;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"}]...
|
-7163596007688455125
|
-1127563140626834290
|
click
|
accessibility
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
Close tab
New Tab
Customize sidebar
Close Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
AI Chat settings
Close
WORK, Google Account: [EMAIL]
Main menu
New chat
Gemini
New Chat
Open menu for conversation actions.
Conversation with Gemini
Conversation with Gemini
Show the uploaded image in a lightbox
Copy prompt
You said Make a PR of changes Find potential issues and bottlenecks
You said
Make a PR of changes Find potential issues and bottlenecks
Listen
Show thinking
Gemini said
Gemini said
I can see you've uploaded a screenshot of a code diff, likely from a version control system given the red and green highlights. I would love to help you review the changes, spot bottlenecks, and help you draft a Pull Request.
However,
the image resolution is far too low for me to read.
It appears to be a completely zoomed-out view where the code has been reduced to tiny, illegible pixels. Because of this, I cannot extract any text or logic to analyze.
How You Can Share the Code
How You Can Share the Code
To help me review your code effectively, please try one of the following:
Paste the text directly:
Copy the specific code blocks (both the old and new versions if possible) and paste them directly into our chat.
Upload the files:
If the changes are extensive, you can upload the raw text or code files.
Take high-resolution screenshots:
If you must use images, take closer, readable screenshots of the specific functions or methods you want me to review.
Once you provide the readable code, I can dive right in to identify potential bugs, assess performance bottlenecks, and help you summarize the changes for your PR!
Good response
Bad response
Share & export
Copy
Show more options
Copy prompt
Edit
You said app/Component/ES/Listeners/UpdateMultipleTargetsListener.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\Component\ES\Listeners; namespace Jiminny\Component\ES\Listeners; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Contracts\ES\Events\UpdateMultipleEntities; use Jiminny\Contracts\ES\Events\UpdateMultipleEntities; use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface; AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntities(), $event->getEntities(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } } } app/Component/ES/Listeners/UpdateSingleTargetListener.php +9-1Lines changed: 9 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Actions\TrackElasticSearchOperations; use Jiminny\Component\ES\Actions\TrackElasticSearchOperations; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Contracts\ES\Events\UpdateSingleEntity; use Jiminny\Contracts\ES\Events\UpdateSingleEntity; use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface; 'entityId' => $event->getEntityId(), 'entityId' => $event->getEntityId(), ]); ]); /** * @important: * Synchronous event should eventually be deprecated. * Instant write operations are blocking and should be used sparingly. * It is much better in terms of performance to write 100 or 1000 documents at once, * and have one blocking reindex operation, instead of writing 10 documents synchronously. */ if ($event->isSyncEvent()) { if ($event->isSyncEvent()) { $this->handleSyncEvent($event); $this->handleSyncEvent($event); AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntityId(), $event->getEntityId(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } app/Component/ES/Processor/Actions/UpsertDocumentsAction.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SimpleCollection; use Jiminny\Component\ES\Processor\DTOs\SimpleCollection; use Jiminny\Component\ES\Processor\ResponseEvaluator; use Jiminny\Component\ES\Processor\ResponseEvaluator; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Exceptions\InvalidDataException; use Jiminny\Exceptions\InvalidDataException; use Sentry\Laravel\Facade as Sentry; use Sentry\Laravel\Facade as Sentry; AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( entityType: $this->updateTarget, entityType: $this->updateTarget, entityId: (int) $document->getId(), entityId: (int) $document->getId(), withPriority: true priority: QueuePriorityEnum::HIGH, ); ); } } app/Component/ES/Processor/DTOs/SelectionList.php +54-17Lines changed: 54 additions & 17 deletions Original file line numberOriginal file lineDiff line numberDiff line change namespace Jiminny\Component\ES\Processor\DTOs; namespace Jiminny\Component\ES\Processor\DTOs; use Jiminny\Component\ES\QueuePriorityEnum; /** /** * A very basic and simple collection of entity IDs. * A very basic and simple collection of entity IDs. */ */ class SelectionList class SelectionList { { public function __construct( private const int DEFAULT_CHUNK = 200; private readonly array $priorityEntityIdList = [], private readonly array $normalEntityIdList = [], private int $chunkSize = self::DEFAULT_CHUNK; private readonly bool $isStaleChunkSelected = false, private bool $isStaleChunkSelected = false; private readonly int $chunkSize = 200, private array $selectedEntityIds = []; ) { // Do nothing public function setChunkSize(int $chunkSize): void { $this->chunkSize = $chunkSize; } } public function getAllIds(): array public function markStale(): void { { return array_merge($this->priorityEntityIdList, $this->normalEntityIdList); $this->isStaleChunkSelected = true; } } public function count(): int public function addEntityList(string|QueuePriorityEnum $priority, array $entityIds): void { { return count($this->priorityEntityIdList) + count($this->normalEntityIdList); $priorityKey = $this->normalisePriority($priority); if (! array_key_exists($priorityKey, $this->selectedEntityIds)) { $this->selectedEntityIds[$priorityKey] = []; } $this->selectedEntityIds[$priorityKey] = array_merge($this->selectedEntityIds[$priorityKey], $entityIds); } } public function isEmpty(): bool /** * @return string[] */ public function getEntityListGroups(): array { { return empty($this->priorityEntityIdList) && empty($this->normalEntityIdList); return array_keys($this->selectedEntityIds); } } public function getHighPriorityEntityIds(): array public function getEntityListItemsByGroup(string|QueuePriorityEnum $priority): array { { return $this->priorityEntityIdList; $priorityKey = $this->normalisePriority($priority); return $this->selectedEntityIds[$priorityKey] ?? []; } } public function getNormalPriorityEntityId(): array public function getAllIds(): array { { return $this->normalEntityIdList; $allIds = []; foreach ($this->selectedEntityIds as $entityIds) { $allIds = array_merge($allIds, $entityIds); } return $allIds; } public function count(): int { return array_sum( array_map('count', $this->selectedEntityIds) ); } public function isEmpty(): bool { return $this->count() === 0; } } public function isStaleChunkSelected(): bool public function isStaleChunkSelected(): bool { { return $this->count() >= $this->chunkSize; return $this->count() >= $this->chunkSize; } } private function normalisePriority(string|QueuePriorityEnum $priority): string { return $priority instanceof QueuePriorityEnum ? $priority->value : $priority; } } } app/Component/ES/Processor/Traits/SelectEntityListTrait.php +27-4Lines changed: 27 additions & 4 deletions Original file line numberOriginal file lineDiff line numberDiff line change use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; /** /** * Build the correct source list name for the type of entity and priority * Build the correct source list name for the type of entity and priority */ */ trait SelectEntityListTrait trait SelectEntityListTrait { { /** * Highest priority queue for data requiring near-instant availability. * Very few entities should be added here, only when absolutely necessary. */ private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; /** * Normal priority queue for normal application operations. * Almost all update events should pass through this queue */ private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; protected static function selectTargetList(string $entityType, bool $withPriority = false): string /** { * Nonblocking low priority queue. This queue will be consumed only when there is nothing * with higher priority. * * This queue will be used for operations such as es:reset-async */ private const string ENTITIES_LOW_PRIORITIES_LIST = '%s-for-update-low'; protected static function selectTargetList( string $entityType, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { if (! in_array($entityType, UpdateTarget::allowedTargets())) { if (! in_array($entityType, UpdateTarget::allowedTargets())) { throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); } } if ($withPriority) { if ($priority->isHigh()) { Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); } } if ($priority->isLow()) { return sprintf(self::ENTITIES_LOW_PRIORITIES_LIST, $entityType); } return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); } } } } app/Component/ES/Processor/TargetEntitiesSelector.php +26-21Lines changed: 26 additions & 21 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SelectionList; use Jiminny\Component\ES\Processor\DTOs\SelectionList; use Jiminny\Component\ES\Processor\Traits\ExtractIdsTrait; use Jiminny\Component\ES\Processor\Traits\ExtractIdsTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\QueuePriorityEnum; /** /** * This class supplies a list of entities pending an update. * This class supplies a list of entities pending an update. public function select(): SelectionList public function select(): SelectionList { { $staleWorkEntityIds = $this->getStaleChunk(); $selectionList = new SelectionList(); $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $staleWorkEntityIds = $this->getStaleChunk(); if (count($staleWorkEntityIds) > 0) { if (count($staleWorkEntityIds) > 0) { return new SelectionList( /** priorityEntityIdList: $staleWorkEntityIds, * Stale chunks are treated as high priority isStaleChunkSelected: true, */ chunkSize: ChunkSize::getStaleChunkSize($this->updateTarget), $selectionList->markStale(); ); $selectionList->addEntityList(QueuePriorityEnum::HIGH, $staleWorkEntityIds); $selectionList->setChunkSize(ChunkSize::getStaleChunkSize($this->updateTarget)); return $selectionList; } } $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $selectionList->setChunkSize($mainChunkSize); $priorityEntityIdsList = $this->extractIdsFromSet( $priorityEntityIdsList = $this->extractIds(QueuePriorityEnum::HIGH, $mainChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, true), $selectionList->addEntityList(QueuePriorityEnum::HIGH, $priorityEntityIdsList); $mainChunkSize, ); $normalEntityIdsList = []; $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); if ($normalEntityChunkSize > 0) { if ($normalEntityChunkSize > 0) { $normalEntityIdsList = $this->extractIdsFromSet( $normalEntityIdsList = $this->extractIds(QueuePriorityEnum::NORMAL, $normalEntityChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, false), $selectionList->addEntityList(QueuePriorityEnum::NORMAL, $normalEntityIdsList); $normalEntityChunkSize ); } } return new SelectionList( return $selectionList; priorityEntityIdList: $priorityEntityIdsList, normalEntityIdList: $normalEntityIdsList, chunkSize: $mainChunkSize ); } } private function getStaleChunk(): array private function getStaleChunk(): array return []; return []; } } private function extractIds(QueuePriorityEnum $priority, int $chunkSize): array { return $this->extractIdsFromSet( AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, $priority), $chunkSize ); } } } app/Component/ES/AsyncUpdateElasticSearch.php +17-10Lines changed: 17 additions & 10 deletions Original file line numberOriginal file lineDiff line numberDiff line change * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * and other activity related data * and other activity related data */ */ public static function markEntityForUpdate(string $entityType, int $entityId, bool $withPriority = false): void public static function markEntityForUpdate( { string $entityType, $targetList = self::selectTargetList($entityType, $withPriority); int $entityId, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { $targetList = self::selectTargetList($entityType, $priority); Redis::sadd($targetList, $entityId); Redis::sadd($targetList, $entityId); Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ 'entityType' => $entityType, 'entityType' => $entityType, 'entityId' => $entityId, 'entityId' => $entityId, 'collectionKey' => $targetList, 'collectionKey' => $targetList, 'withPriority' => $withPriority, 'priority' => $priority->value, ]); ]); } } public static function bulkMarkEntitiesForUpdate( public static function bulkMarkEntitiesForUpdate( string $entityType, string $entityType, array $entityIds, array $entityIds, bool $withPriority = false QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { ): void { if (empty($entityIds)) { if (empty($entityIds)) { return; return; } } $targetList = self::selectTargetList($entityType, $withPriority); $targetList = self::selectTargetList($entityType, $priority); Redis::saddarray($targetList, $entityIds); Redis::saddarray($targetList, $entityIds); } } * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Takes priority into consideration. * Takes priority into consideration. */ */ public static function getEntitiesSourceList(string $updateTarget, $priority = false): string public static function getEntitiesSourceList( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { return self::selectTargetList($updateTarget, $priority); return self::selectTargetList($updateTarget, $priority); } } /** /** * Externally called helper methods * Externally called helper methods * - count and flush * - count and flush */ */ public static function getEntitiesListCount(string $updateTarget, $priority = false): int public static function getEntitiesListCount( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): int { $targetList = self::selectTargetList($updateTarget, $priority); $targetList = self::selectTargetList($updateTarget, $priority); return Redis::scard($targetList); return Redis::scard($targetList); app/Component/ES/QueuePriorityEnum.php +40Lines changed: 40 additions & 0 deletions Original file line numberOriginal file lineDiff line numberDiff line change <?php declare(strict_types=1); namespace Jiminny\Component\ES; use Jiminny\Exceptions\InvalidArgumentException; enum QueuePriorityEnum: string { case HIGH = 'high'; case NORMAL = 'normal'; case LOW = 'low'; public static function tryFromString(string $value): self { if (! self::isValid($value)) { throw new InvalidArgumentException( sprintf('Invalid queue priority "%s" selected', $value) ); } return self::tryFrom($value); } public static function isValid(string $value): bool { return self::tryFrom($value) !== null; } public function isLow(): bool { return $this === self::LOW; } public function isHigh(): bool { return $this === self::HIGH; } } app/Component/ES/UpdateProcessManager.php +12-9Lines changed: 12 additions & 9 deletions Original file line numberOriginal file lineDiff line numberDiff line change if ($selectionList->isEmpty()) { if ($selectionList->isEmpty()) { return false; return false; } } /** /** * A stale chunk will always be smaller than a regular chunk. * A stale chunk will always be smaller than a regular chunk. * That doesn't mean there aren't any other scheduled entities for processing * That doesn't mean there aren't any other scheduled entities for processing private function rescheduleThrottledEntities(SelectionList $selectionList): void private function rescheduleThrottledEntities(SelectionList $selectionList): void { { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $groups = $selectionList->getEntityListGroups(); $this->updateTarget, foreach ($groups as $eachGroup) { $selectionList->getNormalPriorityEntityId() $groupEntityIds = $selectionList->getEntityListItemsByGroup($eachGroup); ); if (! empty($groupEntityIds)) { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $this->updateTarget, entityType: $this->updateTarget, $selectionList->getHighPriorityEntityIds(), entityIds: $groupEntityIds, true priority: QueuePriorityEnum::tryFromString($eachGroup) ); ); } } } } } } app/Console/Commands/Elasticsearch/AsyncUpdateEsEntities.php +9-3Lines changed: 9 additions & 3 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Illuminate\Support\Str; use Illuminate\Support\Str; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Component\ES\UpdateProcessManager; use Jiminny\Component\ES\UpdateProcessManager; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Traits\GracefullyStoppable; use Jiminny\Traits\GracefullyStoppable; Redis::set($gaugeLockName, true); Redis::set($gaugeLockName, true); Redis::expire($gaugeLockName, 60); Redis::expire($gaugeLockName, 60); $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::HIGH), ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update', $updateTarget), stat: sprintf('jiminny.%s-for-update', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::NORMAL), ); ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), stat: sprintf('jiminny.%s-for-update-low', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, true), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::LOW), ); ); } } app/Console/Commands/Elasticsearch/ResetAsyncElasticSearchCommand.php +5-1Lines changed: 5 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\Traits\ValidateUpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\ValidateUpdateTargetTrait; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Component\ES\Repositories\EsResetRepositoryInterface; use Jiminny\Component\ES\Repositories\EsResetRepositoryInterface; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Traits\GracefullyStoppable; use Jiminny\Traits\GracefullyStoppable; private function getRemainingScheduledEntities(bool $printStatus = false): int private function getRemainingScheduledEntities(bool $printStatus = false): int { { $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget, true); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount( $this->updateTarget, QueuePriorityEnum::HIGH ); if ($printStatus) { if ($printStatus) { $this->line( $this->line(
You said
app/Component/ES/Listeners/UpdateMultipleTargetsListener.php
+2-1Lines changed: 2 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\Component\ES\Listeners;
namespace Jiminny\Component\ES\Listeners;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\QueuePriorityEnum;
use Jiminny\Contracts\ES\Events\UpdateMultipleEntities;
use Jiminny\Contracts\ES\Events\UpdateMultipleEntities;
use Psr\Log\LoggerInterface;
use Psr\Log\LoggerInterface;
AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(
AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(
$event->getUpdateTargetValue(),
$event->getUpdateTargetValue(),
$event->getEntities(),
$event->getEntities(),
$event->isPriority()
$event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL,
);
);
}
}
}
}
app/Component/ES/Listeners/UpdateSingleTargetListener.php
+9-1Lines changed: 9 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Actions\TrackElasticSearchOperations;
use Jiminny\Component\ES\Actions\TrackElasticSearchOperations;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\Processor\EntityQueryBuilder;
use Jiminny\Component\ES\Processor\EntityQueryBuilder;
use Jiminny\Component\ES\QueuePriorityEnum;
use Jiminny\Contracts\ES\Events\UpdateSingleEntity;
use Jiminny\Contracts\ES\Events\UpdateSingleEntity;
use Psr\Log\LoggerInterface;
use Psr\Log\LoggerInterface;
'entityId' => $event->getEntityId(),
'entityId' => $event->getEntityId(),
]);
]);
/**
* @important:
* Synchronous event should eventually be deprecated.
* Instant write operations are blocking and should be used sparingly.
* It is much better in terms of performance to write 100 or 1000 documents at once,
* and have one blocking reindex operation, instead of writing 10 documents synchronously.
*/
if ($event->isSyncEvent()) {
if ($event->isSyncEvent()) {
$this->handleSyncEvent($event);
$this->handleSyncEvent($event);
AsyncUpdateElasticSearch::markEntityForUpdate(
AsyncUpdateElasticSearch::markEntityForUpdate(
$event->getUpdateTargetValue(),
$event->getUpdateTargetValue(),
$event->getEntityId(),
$event->getEntityId(),
$event->isPriority()
$event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL,
);
);
}
}
app/Component/ES/Processor/Actions/UpsertDocumentsAction.php
+2-1Lines changed: 2 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SimpleCollection;
use Jiminny\Component\ES\Processor\DTOs\SimpleCollection;
use Jiminny\Component\ES\Processor\ResponseEvaluator;
use Jiminny\Component\ES\Processor\ResponseEvaluator;
use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait;
use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait;
use Jiminny\Component\ES\QueuePriorityEnum;
use Jiminny\Exceptions\InvalidDataException;...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
55692
|
1932
|
12
|
2026-05-19T06:40:51.645325+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779172851645_m1.jpg...
|
Firefox
|
JY-20808 low priority indexing queue by Vasil-Jimi JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app — Work...
|
1
|
github.com/jiminny/app/pull/12082/changes#diff-005 github.com/jiminny/app/pull/12082/changes#diff-00566b80af55fe41e9ad53dabe5735494b207ecf2d8da23f7436862fa9cf0d0a...
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
Close tab
New Tab
Customize sidebar
Close Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
AI Chat settings
Close
WORK, Google Account: [EMAIL]
Main menu
New chat
Gemini
New Chat
Open menu for conversation actions.
Conversation with Gemini
Conversation with Gemini
Show the uploaded image in a lightbox
Copy prompt
You said Make a PR of changes Find potential issues and bottlenecks
You said
Make a PR of changes Find potential issues and bottlenecks
Listen
Show thinking
Gemini said
Gemini said
I can see you've uploaded a screenshot of a code diff, likely from a version control system given the red and green highlights. I would love to help you review the changes, spot bottlenecks, and help you draft a Pull Request.
However,
the image resolution is far too low for me to read.
It appears to be a completely zoomed-out view where the code has been reduced to tiny, illegible pixels. Because of this, I cannot extract any text or logic to analyze.
How You Can Share the Code
How You Can Share the Code
To help me review your code effectively, please try one of the following:
Paste the text directly:
Copy the specific code blocks (both the old and new versions if possible) and paste them directly into our chat.
Upload the files:
If the changes are extensive, you can upload the raw text or code files.
Take high-resolution screenshots:
If you must use images, take closer, readable screenshots of the specific functions or methods you want me to review.
Once you provide the readable code, I can dive right in to identify potential bugs, assess performance bottlenecks, and help you summarize the changes for your PR!
Good response
Bad response
Share & export
Copy
Show more options
Copy prompt
Edit
You said app/Component/ES/Listeners/UpdateMultipleTargetsListener.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\Component\ES\Listeners; namespace Jiminny\Component\ES\Listeners; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Contracts\ES\Events\UpdateMultipleEntities; use Jiminny\Contracts\ES\Events\UpdateMultipleEntities; use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface; AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntities(), $event->getEntities(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } } } app/Component/ES/Listeners/UpdateSingleTargetListener.php +9-1Lines changed: 9 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Actions\TrackElasticSearchOperations; use Jiminny\Component\ES\Actions\TrackElasticSearchOperations; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Contracts\ES\Events\UpdateSingleEntity; use Jiminny\Contracts\ES\Events\UpdateSingleEntity; use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface; 'entityId' => $event->getEntityId(), 'entityId' => $event->getEntityId(), ]); ]); /** * @important: * Synchronous event should eventually be deprecated. * Instant write operations are blocking and should be used sparingly. * It is much better in terms of performance to write 100 or 1000 documents at once, * and have one blocking reindex operation, instead of writing 10 documents synchronously. */ if ($event->isSyncEvent()) { if ($event->isSyncEvent()) { $this->handleSyncEvent($event); $this->handleSyncEvent($event); AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntityId(), $event->getEntityId(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } app/Component/ES/Processor/Actions/UpsertDocumentsAction.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SimpleCollection; use Jiminny\Component\ES\Processor\DTOs\SimpleCollection; use Jiminny\Component\ES\Processor\ResponseEvaluator; use Jiminny\Component\ES\Processor\ResponseEvaluator; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Exceptions\InvalidDataException; use Jiminny\Exceptions\InvalidDataException; use Sentry\Laravel\Facade as Sentry; use Sentry\Laravel\Facade as Sentry; AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( entityType: $this->updateTarget, entityType: $this->updateTarget, entityId: (int) $document->getId(), entityId: (int) $document->getId(), withPriority: true priority: QueuePriorityEnum::HIGH, ); ); } } app/Component/ES/Processor/DTOs/SelectionList.php +54-17Lines changed: 54 additions & 17 deletions Original file line numberOriginal file lineDiff line numberDiff line change namespace Jiminny\Component\ES\Processor\DTOs; namespace Jiminny\Component\ES\Processor\DTOs; use Jiminny\Component\ES\QueuePriorityEnum; /** /** * A very basic and simple collection of entity IDs. * A very basic and simple collection of entity IDs. */ */ class SelectionList class SelectionList { { public function __construct( private const int DEFAULT_CHUNK = 200; private readonly array $priorityEntityIdList = [], private readonly array $normalEntityIdList = [], private int $chunkSize = self::DEFAULT_CHUNK; private readonly bool $isStaleChunkSelected = false, private bool $isStaleChunkSelected = false; private readonly int $chunkSize = 200, private array $selectedEntityIds = []; ) { // Do nothing public function setChunkSize(int $chunkSize): void { $this->chunkSize = $chunkSize; } } public function getAllIds(): array public function markStale(): void { { return array_merge($this->priorityEntityIdList, $this->normalEntityIdList); $this->isStaleChunkSelected = true; } } public function count(): int public function addEntityList(string|QueuePriorityEnum $priority, array $entityIds): void { { return count($this->priorityEntityIdList) + count($this->normalEntityIdList); $priorityKey = $this->normalisePriority($priority); if (! array_key_exists($priorityKey, $this->selectedEntityIds)) { $this->selectedEntityIds[$priorityKey] = []; } $this->selectedEntityIds[$priorityKey] = array_merge($this->selectedEntityIds[$priorityKey], $entityIds); } } public function isEmpty(): bool /** * @return string[] */ public function getEntityListGroups(): array { { return empty($this->priorityEntityIdList) && empty($this->normalEntityIdList); return array_keys($this->selectedEntityIds); } } public function getHighPriorityEntityIds(): array public function getEntityListItemsByGroup(string|QueuePriorityEnum $priority): array { { return $this->priorityEntityIdList; $priorityKey = $this->normalisePriority($priority); return $this->selectedEntityIds[$priorityKey] ?? []; } } public function getNormalPriorityEntityId(): array public function getAllIds(): array { { return $this->normalEntityIdList; $allIds = []; foreach ($this->selectedEntityIds as $entityIds) { $allIds = array_merge($allIds, $entityIds); } return $allIds; } public function count(): int { return array_sum( array_map('count', $this->selectedEntityIds) ); } public function isEmpty(): bool { return $this->count() === 0; } } public function isStaleChunkSelected(): bool public function isStaleChunkSelected(): bool { { return $this->count() >= $this->chunkSize; return $this->count() >= $this->chunkSize; } } private function normalisePriority(string|QueuePriorityEnum $priority): string { return $priority instanceof QueuePriorityEnum ? $priority->value : $priority; } } } app/Component/ES/Processor/Traits/SelectEntityListTrait.php +27-4Lines changed: 27 additions & 4 deletions Original file line numberOriginal file lineDiff line numberDiff line change use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; /** /** * Build the correct source list name for the type of entity and priority * Build the correct source list name for the type of entity and priority */ */ trait SelectEntityListTrait trait SelectEntityListTrait { { /** * Highest priority queue for data requiring near-instant availability. * Very few entities should be added here, only when absolutely necessary. */ private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; /** * Normal priority queue for normal application operations. * Almost all update events should pass through this queue */ private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; protected static function selectTargetList(string $entityType, bool $withPriority = false): string /** { * Nonblocking low priority queue. This queue will be consumed only when there is nothing * with higher priority. * * This queue will be used for operations such as es:reset-async */ private const string ENTITIES_LOW_PRIORITIES_LIST = '%s-for-update-low'; protected static function selectTargetList( string $entityType, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { if (! in_array($entityType, UpdateTarget::allowedTargets())) { if (! in_array($entityType, UpdateTarget::allowedTargets())) { throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); } } if ($withPriority) { if ($priority->isHigh()) { Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); } } if ($priority->isLow()) { return sprintf(self::ENTITIES_LOW_PRIORITIES_LIST, $entityType); } return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); } } } } app/Component/ES/Processor/TargetEntitiesSelector.php +26-21Lines changed: 26 additions & 21 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SelectionList; use Jiminny\Component\ES\Processor\DTOs\SelectionList; use Jiminny\Component\ES\Processor\Traits\ExtractIdsTrait; use Jiminny\Component\ES\Processor\Traits\ExtractIdsTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\QueuePriorityEnum; /** /** * This class supplies a list of entities pending an update. * This class supplies a list of entities pending an update. public function select(): SelectionList public function select(): SelectionList { { $staleWorkEntityIds = $this->getStaleChunk(); $selectionList = new SelectionList(); $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $staleWorkEntityIds = $this->getStaleChunk(); if (count($staleWorkEntityIds) > 0) { if (count($staleWorkEntityIds) > 0) { return new SelectionList( /** priorityEntityIdList: $staleWorkEntityIds, * Stale chunks are treated as high priority isStaleChunkSelected: true, */ chunkSize: ChunkSize::getStaleChunkSize($this->updateTarget), $selectionList->markStale(); ); $selectionList->addEntityList(QueuePriorityEnum::HIGH, $staleWorkEntityIds); $selectionList->setChunkSize(ChunkSize::getStaleChunkSize($this->updateTarget)); return $selectionList; } } $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $selectionList->setChunkSize($mainChunkSize); $priorityEntityIdsList = $this->extractIdsFromSet( $priorityEntityIdsList = $this->extractIds(QueuePriorityEnum::HIGH, $mainChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, true), $selectionList->addEntityList(QueuePriorityEnum::HIGH, $priorityEntityIdsList); $mainChunkSize, ); $normalEntityIdsList = []; $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); if ($normalEntityChunkSize > 0) { if ($normalEntityChunkSize > 0) { $normalEntityIdsList = $this->extractIdsFromSet( $normalEntityIdsList = $this->extractIds(QueuePriorityEnum::NORMAL, $normalEntityChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, false), $selectionList->addEntityList(QueuePriorityEnum::NORMAL, $normalEntityIdsList); $normalEntityChunkSize ); } } return new SelectionList( return $selectionList; priorityEntityIdList: $priorityEntityIdsList, normalEntityIdList: $normalEntityIdsList, chunkSize: $mainChunkSize ); } } private function getStaleChunk(): array private function getStaleChunk(): array return []; return []; } } private function extractIds(QueuePriorityEnum $priority, int $chunkSize): array { return $this->extractIdsFromSet( AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, $priority), $chunkSize ); } } } app/Component/ES/AsyncUpdateElasticSearch.php +17-10Lines changed: 17 additions & 10 deletions Original file line numberOriginal file lineDiff line numberDiff line change * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * and other activity related data * and other activity related data */ */ public static function markEntityForUpdate(string $entityType, int $entityId, bool $withPriority = false): void public static function markEntityForUpdate( { string $entityType, $targetList = self::selectTargetList($entityType, $withPriority); int $entityId, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { $targetList = self::selectTargetList($entityType, $priority); Redis::sadd($targetList, $entityId); Redis::sadd($targetList, $entityId); Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ 'entityType' => $entityType, 'entityType' => $entityType, 'entityId' => $entityId, 'entityId' => $entityId, 'collectionKey' => $targetList, 'collectionKey' => $targetList, 'withPriority' => $withPriority, 'priority' => $priority->value, ]); ]); } } public static function bulkMarkEntitiesForUpdate( public static function bulkMarkEntitiesForUpdate( string $entityType, string $entityType, array $entityIds, array $entityIds, bool $withPriority = false QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { ): void { if (empty($entityIds)) { if (empty($entityIds)) { return; return; } } $targetList = self::selectTargetList($entityType, $withPriority); $targetList = self::selectTargetList($entityType, $priority); Redis::saddarray($targetList, $entityIds); Redis::saddarray($targetList, $entityIds); } } * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Takes priority into consideration. * Takes priority into consideration. */ */ public static function getEntitiesSourceList(string $updateTarget, $priority = false): string public static function getEntitiesSourceList( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { return self::selectTargetList($updateTarget, $priority); return self::selectTargetList($updateTarget, $priority); } } /** /** * Externally called helper methods * Externally called helper methods * - count and flush * - count and flush */ */ public static function getEntitiesListCount(string $updateTarget, $priority = false): int public static function getEntitiesListCount( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): int { $targetList = self::selectTargetList($updateTarget, $priority); $targetList = self::selectTargetList($updateTarget, $priority); return Redis::scard($targetList); return Redis::scard($targetList); app/Component/ES/QueuePriorityEnum.php +40Lines changed: 40 additions & 0 deletions Original file line numberOriginal file lineDiff line numberDiff line change <?php declare(strict_types=1); namespace Jiminny\Component\ES; use Jiminny\Exceptions\InvalidArgumentException; enum QueuePriorityEnum: string { case HIGH = 'high'; case NORMAL = 'normal'; case LOW = 'low'; public static function tryFromString(string $value): self { if (! self::isValid($value)) { throw new InvalidArgumentException( sprintf('Invalid queue priority "%s" selected', $value) ); } return self::tryFrom($value); } public static function isValid(string $value): bool { return self::tryFrom($value) !== null; } public function isLow(): bool { return $this === self::LOW; } public function isHigh(): bool { return $this === self::HIGH; } } app/Component/ES/UpdateProcessManager.php +12-9Lines changed: 12 additions & 9 deletions Original file line numberOriginal file lineDiff line numberDiff line change if ($selectionList->isEmpty()) { if ($selectionList->isEmpty()) { return false; return false; } } /** /** * A stale chunk will always be smaller than a regular chunk. * A stale chunk will always be smaller than a regular chunk. * That doesn't mean there aren't any other scheduled entities for processing * That doesn't mean there aren't any other scheduled entities for processing private function rescheduleThrottledEntities(SelectionList $selectionList): void private function rescheduleThrottledEntities(SelectionList $selectionList): void { { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $groups = $selectionList->getEntityListGroups(); $this->updateTarget, foreach ($groups as $eachGroup) { $selectionList->getNormalPriorityEntityId() $groupEntityIds = $selectionList->getEntityListItemsByGroup($eachGroup); ); if (! empty($groupEntityIds)) { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $this->updateTarget, entityType: $this->updateTarget, $selectionList->getHighPriorityEntityIds(), entityIds: $groupEntityIds, true priority: QueuePriorityEnum::tryFromString($eachGroup) ); ); } } } } } } app/Console/Commands/Elasticsearch/AsyncUpdateEsEntities.php +9-3Lines changed: 9 additions & 3 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Illuminate\Support\Str; use Illuminate\Support\Str; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Component\ES\UpdateProcessManager; use Jiminny\Component\ES\UpdateProcessManager; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Traits\GracefullyStoppable; use Jiminny\Traits\GracefullyStoppable; Redis::set($gaugeLockName, true); Redis::set($gaugeLockName, true); Redis::expire($gaugeLockName, 60); Redis::expire($gaugeLockName, 60); $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::HIGH), ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update', $updateTarget), stat: sprintf('jiminny.%s-for-update', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::NORMAL), ); ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), stat: sprintf('jiminny.%s-for-update-low', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, true), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::LOW), ); ); } } app/Console/Commands/Elasticsearch/ResetAsyncElasticSearchCommand.php +5-1Lines changed: 5 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\Traits\ValidateUpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\ValidateUpdateTargetTrait; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Component\ES\Repositories\EsResetRepositoryInterface; use Jiminny\Component\ES\Repositories\EsResetRepositoryInterface; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Traits\GracefullyStoppable; use Jiminny\Traits\GracefullyStoppable; private function getRemainingScheduledEntities(bool $printStatus = false): int private function getRemainingScheduledEntities(bool $printStatus = false): int { { $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget, true); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount( $this->updateTarget, QueuePriorityEnum::HIGH ); if ($printStatus) { if ($printStatus) { $this->line( $this->line(
You said
app/Component/ES/Listeners/UpdateMultipleTargetsListener.php
+2-1Lines changed: 2 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\Component\ES\Listeners;
namespace Jiminny\Component\ES\Listeners;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\QueuePriorityEnum;
use Jiminny\Contracts\ES\Events\UpdateMultipleEntities;
use Jiminny\Contracts\ES\Events\UpdateMultipleEntities;
use Psr\Log\LoggerInterface;
use Psr\Log\LoggerInterface;
AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(
AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(
$event->getUpdateTargetValue(),
$event->getUpdateTargetValue(),
$event->getEntities(),
$event->getEntities(),
$event->isPriority()
$event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL,
);
);
}
}
}
}
app/Component/ES/Listeners/UpdateSingleTargetListener.php
+9-1Lines changed: 9 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Actions\TrackElasticSearchOperations;
use Jiminny\Component\ES\Actions\TrackElasticSearchOperations;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\Processor\EntityQueryBuilder;
use Jiminny\Component\ES\Processor\EntityQueryBuilder;
use Jiminny\Component\ES\QueuePriorityEnum;
use Jiminny\Contracts\ES\Events\UpdateSingleEntity;
use Jiminny\Contracts\ES\Events\UpdateSingleEntity;
use Psr\Log\LoggerInterface;
use Psr\Log\LoggerInterface;
'entityId' => $event->getEntityId(),
'entityId' => $event->getEntityId(),
]);
]);
/**
* @important:
* Synchronous event should eventually be deprecated.
* Instant write operations are blocking and should be used sparingly.
* It is much better in terms of performance to write 100 or 1000 documents at once,
* and have one blocking reindex operation, instead of writing 10 documents synchronously.
*/
if ($event->isSyncEvent()) {
if ($event->isSyncEvent()) {
$this->handleSyncEvent($event);
$this->handleSyncEvent($event);
AsyncUpdateElasticSearch::markEntityForUpdate(
AsyncUpdateElasticSearch::markEntityForUpdate(
$event->getUpdateTargetValue(),
$event->getUpdateTargetValue(),
$event->getEntityId(),
$event->getEntityId(),
$event->isPriority()
$event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL,
);
);
}
}
app/Component/ES/Processor/Actions/UpsertDocumentsAction.php
+2-1Lines changed: 2 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SimpleCollection;
use Jiminny\Component\ES\Processor\DTOs\SimpleCollection;
use Jiminny\Component\ES\Processor\ResponseEvaluator;
use Jiminny\Component\ES\Processor\ResponseEvaluator;
use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait;
use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait;
use Jiminny\Component\ES\QueuePriorityEnum;
use Jiminny\Exceptions\InvalidDataException;
use Jiminny\Exceptions\InvalidDataException;
use Sentry\Laravel\Facade as Sentry;
use Sentry\Laravel\Facade as Sentry;
AsyncUpdateElasticSearch::markEntityForUpdate(
AsyncUpdateElasticSearch::markEntityForUpdate(
entityType: $this->updateTarget,
entityType: $this->updateTarget,
entityId: (int) $document->getId(),
entityId: (int) $document->getId(),
withPriority: true
priority: QueuePriorityEnum::HIGH,
);
);
}
}
app/Component/ES/Processor/DTOs/SelectionList.php
+54-17Lines changed: 54 additions & 17 deletions
Original file line numberOriginal file lineDiff line numberDiff line change
namespace Jiminny\Component\ES\Processor\DTOs;
namespace Jiminny\Component\ES\Processor\DTOs;
use Jiminny\Component\ES\QueuePriorityEnum;
/**
/**
* A very basic and simple collection of entity IDs.
* A very basic and simple collection of entity IDs.
*/
*/
class SelectionList
class SelectionList
{
{
public function __construct(
private const int DEFAULT_CHUNK = 200;
private readonly array $priorityEntityIdList = [],
private readonly array $normalEntityIdList = [],
private int $chunkSize = self::DEFAULT_CHUNK;
private readonly bool $isStaleChunkSelected = false,
private bool $isStaleChunkSelected = false;
private readonly int $chunkSize = 200,
private array $selectedEntityIds = [];
) {
// Do nothing
public function setChunkSize(int $chunkSize): void
{
$this->chunkSize = $chunkSize;
}
}
public function getAllIds(): array
public function markStale(): void
{
{
return array_merge($this->priorityEntityIdList, $this->normalEntityIdList);
$this->isStaleChunkSelected = true;
}
}
public function count(): int
public function addEntityList(string|QueuePriorityEnum $priority, array $entityIds): void
{
{
return count($this->priorityEntityIdList) + count($this->normalEntityIdList);
$priorityKey = $this->normalisePriority($priority);
if (! array_key_exists($priorityKey, $this->selectedEntityIds)) {
$this->selectedEntityIds[$priorityKey] = [];
}
$this->selectedEntityIds[$priorityKey] = array_merge($this->selectedEntityIds[$priorityKey], $entityIds);
}
}
public function isEmpty(): bool
/**
* @return string[]
*/
public function getEntityListGroups(): array
{
{
return empty($this->priorityEntityIdList) && empty($this->normalEntityIdList);
return array_keys($this->selectedEntityIds);
}
}
public function getHighPriorityEntityIds(): array
public function getEntityListItemsByGroup(string|QueuePriorityEnum $priority): array
{
{
return $this->priorityEntityIdList;
$priorityKey = $this->normalisePriority($priority);
return $this->selectedEntityIds[$priorityKey] ?? [];
}
}
public function getNormalPriorityEntityId(): array
public function getAllIds(): array
{
{
return $this->normalEntityIdList;
$allIds = [];
foreach ($this->selectedEntityIds as $entityIds) {
$allIds = array_merge($allIds, $entityIds);
}
return $allIds;
}
public function count(): int
{
return array_sum(
array_map('count', $this->selectedEntityIds)
);
}
public function isEmpty(): bool
{
return $this->count() === 0;
}
}
public function isStaleChunkSelected(): bool...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New Tab","depth":4,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Close Google Gemini (⌃X)","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Tabs from other devices","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"AI Chat settings","depth":7,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Close","depth":7,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"WORK, Google Account: lukas.kovalik@jiminny.com","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Main menu","depth":12,"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New chat","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Gemini","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"New Chat","depth":12,"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Open menu for conversation actions.","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXHeading","text":"Conversation with Gemini","depth":15,"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Conversation with Gemini","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Show the uploaded image in a lightbox","depth":21,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy prompt","depth":21,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"You said Make a PR of changes Find potential issues and bottlenecks","depth":21,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"You said","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Make a PR of changes Find potential issues and bottlenecks","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Listen","depth":22,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Show thinking","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Gemini said","depth":20,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Gemini said","depth":21,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"I can see you've uploaded a screenshot of a code diff, likely from a version control system given the red and green highlights. I would love to help you review the changes, spot bottlenecks, and help you draft a Pull Request.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"However,","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"the image resolution is far too low for me to read.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"It appears to be a completely zoomed-out view where the code has been reduced to tiny, illegible pixels. Because of this, I cannot extract any text or logic to analyze.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"How You Can Share the Code","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"How You Can Share the Code","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"To help me review your code effectively, please try one of the following:","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Paste the text directly:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Copy the specific code blocks (both the old and new versions if possible) and paste them directly into our chat.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Upload the files:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"If the changes are extensive, you can upload the raw text or code files.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Take high-resolution screenshots:","depth":26,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"If you must use images, take closer, readable screenshots of the specific functions or methods you want me to review.","depth":26,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Once you provide the readable code, I can dive right in to identify potential bugs, assess performance bottlenecks, and help you summarize the changes for your PR!","depth":24,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Good response","depth":22,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Bad response","depth":22,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Share & export","depth":21,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy","depth":22,"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Show more options","depth":21,"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy prompt","depth":21,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Edit","depth":21,"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"You said app/Component/ES/Listeners/UpdateMultipleTargetsListener.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\\Component\\ES\\Listeners; namespace Jiminny\\Component\\ES\\Listeners; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Contracts\\ES\\Events\\UpdateMultipleEntities; use Jiminny\\Contracts\\ES\\Events\\UpdateMultipleEntities; use Psr\\Log\\LoggerInterface; use Psr\\Log\\LoggerInterface; AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntities(), $event->getEntities(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } } } app/Component/ES/Listeners/UpdateSingleTargetListener.php +9-1Lines changed: 9 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Actions\\TrackElasticSearchOperations; use Jiminny\\Component\\ES\\Actions\\TrackElasticSearchOperations; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder; use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Contracts\\ES\\Events\\UpdateSingleEntity; use Jiminny\\Contracts\\ES\\Events\\UpdateSingleEntity; use Psr\\Log\\LoggerInterface; use Psr\\Log\\LoggerInterface; 'entityId' => $event->getEntityId(), 'entityId' => $event->getEntityId(), ]); ]); /** * @important: * Synchronous event should eventually be deprecated. * Instant write operations are blocking and should be used sparingly. * It is much better in terms of performance to write 100 or 1000 documents at once, * and have one blocking reindex operation, instead of writing 10 documents synchronously. */ if ($event->isSyncEvent()) { if ($event->isSyncEvent()) { $this->handleSyncEvent($event); $this->handleSyncEvent($event); AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntityId(), $event->getEntityId(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } app/Component/ES/Processor/Actions/UpsertDocumentsAction.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Processor\\DTOs\\SimpleCollection; use Jiminny\\Component\\ES\\Processor\\DTOs\\SimpleCollection; use Jiminny\\Component\\ES\\Processor\\ResponseEvaluator; use Jiminny\\Component\\ES\\Processor\\ResponseEvaluator; use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait; use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Exceptions\\InvalidDataException; use Jiminny\\Exceptions\\InvalidDataException; use Sentry\\Laravel\\Facade as Sentry; use Sentry\\Laravel\\Facade as Sentry; AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( entityType: $this->updateTarget, entityType: $this->updateTarget, entityId: (int) $document->getId(), entityId: (int) $document->getId(), withPriority: true priority: QueuePriorityEnum::HIGH, ); ); } } app/Component/ES/Processor/DTOs/SelectionList.php +54-17Lines changed: 54 additions & 17 deletions Original file line numberOriginal file lineDiff line numberDiff line change namespace Jiminny\\Component\\ES\\Processor\\DTOs; namespace Jiminny\\Component\\ES\\Processor\\DTOs; use Jiminny\\Component\\ES\\QueuePriorityEnum; /** /** * A very basic and simple collection of entity IDs. * A very basic and simple collection of entity IDs. */ */ class SelectionList class SelectionList { { public function __construct( private const int DEFAULT_CHUNK = 200; private readonly array $priorityEntityIdList = [], private readonly array $normalEntityIdList = [], private int $chunkSize = self::DEFAULT_CHUNK; private readonly bool $isStaleChunkSelected = false, private bool $isStaleChunkSelected = false; private readonly int $chunkSize = 200, private array $selectedEntityIds = []; ) { // Do nothing public function setChunkSize(int $chunkSize): void { $this->chunkSize = $chunkSize; } } public function getAllIds(): array public function markStale(): void { { return array_merge($this->priorityEntityIdList, $this->normalEntityIdList); $this->isStaleChunkSelected = true; } } public function count(): int public function addEntityList(string|QueuePriorityEnum $priority, array $entityIds): void { { return count($this->priorityEntityIdList) + count($this->normalEntityIdList); $priorityKey = $this->normalisePriority($priority); if (! array_key_exists($priorityKey, $this->selectedEntityIds)) { $this->selectedEntityIds[$priorityKey] = []; } $this->selectedEntityIds[$priorityKey] = array_merge($this->selectedEntityIds[$priorityKey], $entityIds); } } public function isEmpty(): bool /** * @return string[] */ public function getEntityListGroups(): array { { return empty($this->priorityEntityIdList) && empty($this->normalEntityIdList); return array_keys($this->selectedEntityIds); } } public function getHighPriorityEntityIds(): array public function getEntityListItemsByGroup(string|QueuePriorityEnum $priority): array { { return $this->priorityEntityIdList; $priorityKey = $this->normalisePriority($priority); return $this->selectedEntityIds[$priorityKey] ?? []; } } public function getNormalPriorityEntityId(): array public function getAllIds(): array { { return $this->normalEntityIdList; $allIds = []; foreach ($this->selectedEntityIds as $entityIds) { $allIds = array_merge($allIds, $entityIds); } return $allIds; } public function count(): int { return array_sum( array_map('count', $this->selectedEntityIds) ); } public function isEmpty(): bool { return $this->count() === 0; } } public function isStaleChunkSelected(): bool public function isStaleChunkSelected(): bool { { return $this->count() >= $this->chunkSize; return $this->count() >= $this->chunkSize; } } private function normalisePriority(string|QueuePriorityEnum $priority): string { return $priority instanceof QueuePriorityEnum ? $priority->value : $priority; } } } app/Component/ES/Processor/Traits/SelectEntityListTrait.php +27-4Lines changed: 27 additions & 4 deletions Original file line numberOriginal file lineDiff line numberDiff line change use Illuminate\\Support\\Facades\\Log; use Illuminate\\Support\\Facades\\Log; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Exceptions\\InvalidArgumentException; use Jiminny\\Exceptions\\InvalidArgumentException; /** /** * Build the correct source list name for the type of entity and priority * Build the correct source list name for the type of entity and priority */ */ trait SelectEntityListTrait trait SelectEntityListTrait { { /** * Highest priority queue for data requiring near-instant availability. * Very few entities should be added here, only when absolutely necessary. */ private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; /** * Normal priority queue for normal application operations. * Almost all update events should pass through this queue */ private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; protected static function selectTargetList(string $entityType, bool $withPriority = false): string /** { * Nonblocking low priority queue. This queue will be consumed only when there is nothing * with higher priority. * * This queue will be used for operations such as es:reset-async */ private const string ENTITIES_LOW_PRIORITIES_LIST = '%s-for-update-low'; protected static function selectTargetList( string $entityType, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { if (! in_array($entityType, UpdateTarget::allowedTargets())) { if (! in_array($entityType, UpdateTarget::allowedTargets())) { throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); } } if ($withPriority) { if ($priority->isHigh()) { Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); } } if ($priority->isLow()) { return sprintf(self::ENTITIES_LOW_PRIORITIES_LIST, $entityType); } return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); } } } } app/Component/ES/Processor/TargetEntitiesSelector.php +26-21Lines changed: 26 additions & 21 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Processor\\DTOs\\SelectionList; use Jiminny\\Component\\ES\\Processor\\DTOs\\SelectionList; use Jiminny\\Component\\ES\\Processor\\Traits\\ExtractIdsTrait; use Jiminny\\Component\\ES\\Processor\\Traits\\ExtractIdsTrait; use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait; use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait; use Jiminny\\Component\\ES\\QueuePriorityEnum; /** /** * This class supplies a list of entities pending an update. * This class supplies a list of entities pending an update. public function select(): SelectionList public function select(): SelectionList { { $staleWorkEntityIds = $this->getStaleChunk(); $selectionList = new SelectionList(); $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $staleWorkEntityIds = $this->getStaleChunk(); if (count($staleWorkEntityIds) > 0) { if (count($staleWorkEntityIds) > 0) { return new SelectionList( /** priorityEntityIdList: $staleWorkEntityIds, * Stale chunks are treated as high priority isStaleChunkSelected: true, */ chunkSize: ChunkSize::getStaleChunkSize($this->updateTarget), $selectionList->markStale(); ); $selectionList->addEntityList(QueuePriorityEnum::HIGH, $staleWorkEntityIds); $selectionList->setChunkSize(ChunkSize::getStaleChunkSize($this->updateTarget)); return $selectionList; } } $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $selectionList->setChunkSize($mainChunkSize); $priorityEntityIdsList = $this->extractIdsFromSet( $priorityEntityIdsList = $this->extractIds(QueuePriorityEnum::HIGH, $mainChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, true), $selectionList->addEntityList(QueuePriorityEnum::HIGH, $priorityEntityIdsList); $mainChunkSize, ); $normalEntityIdsList = []; $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); if ($normalEntityChunkSize > 0) { if ($normalEntityChunkSize > 0) { $normalEntityIdsList = $this->extractIdsFromSet( $normalEntityIdsList = $this->extractIds(QueuePriorityEnum::NORMAL, $normalEntityChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, false), $selectionList->addEntityList(QueuePriorityEnum::NORMAL, $normalEntityIdsList); $normalEntityChunkSize ); } } return new SelectionList( return $selectionList; priorityEntityIdList: $priorityEntityIdsList, normalEntityIdList: $normalEntityIdsList, chunkSize: $mainChunkSize ); } } private function getStaleChunk(): array private function getStaleChunk(): array return []; return []; } } private function extractIds(QueuePriorityEnum $priority, int $chunkSize): array { return $this->extractIdsFromSet( AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, $priority), $chunkSize ); } } } app/Component/ES/AsyncUpdateElasticSearch.php +17-10Lines changed: 17 additions & 10 deletions Original file line numberOriginal file lineDiff line numberDiff line change * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * and other activity related data * and other activity related data */ */ public static function markEntityForUpdate(string $entityType, int $entityId, bool $withPriority = false): void public static function markEntityForUpdate( { string $entityType, $targetList = self::selectTargetList($entityType, $withPriority); int $entityId, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { $targetList = self::selectTargetList($entityType, $priority); Redis::sadd($targetList, $entityId); Redis::sadd($targetList, $entityId); Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ 'entityType' => $entityType, 'entityType' => $entityType, 'entityId' => $entityId, 'entityId' => $entityId, 'collectionKey' => $targetList, 'collectionKey' => $targetList, 'withPriority' => $withPriority, 'priority' => $priority->value, ]); ]); } } public static function bulkMarkEntitiesForUpdate( public static function bulkMarkEntitiesForUpdate( string $entityType, string $entityType, array $entityIds, array $entityIds, bool $withPriority = false QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { ): void { if (empty($entityIds)) { if (empty($entityIds)) { return; return; } } $targetList = self::selectTargetList($entityType, $withPriority); $targetList = self::selectTargetList($entityType, $priority); Redis::saddarray($targetList, $entityIds); Redis::saddarray($targetList, $entityIds); } } * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Takes priority into consideration. * Takes priority into consideration. */ */ public static function getEntitiesSourceList(string $updateTarget, $priority = false): string public static function getEntitiesSourceList( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { return self::selectTargetList($updateTarget, $priority); return self::selectTargetList($updateTarget, $priority); } } /** /** * Externally called helper methods * Externally called helper methods * - count and flush * - count and flush */ */ public static function getEntitiesListCount(string $updateTarget, $priority = false): int public static function getEntitiesListCount( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): int { $targetList = self::selectTargetList($updateTarget, $priority); $targetList = self::selectTargetList($updateTarget, $priority); return Redis::scard($targetList); return Redis::scard($targetList); app/Component/ES/QueuePriorityEnum.php +40Lines changed: 40 additions & 0 deletions Original file line numberOriginal file lineDiff line numberDiff line change <?php declare(strict_types=1); namespace Jiminny\\Component\\ES; use Jiminny\\Exceptions\\InvalidArgumentException; enum QueuePriorityEnum: string { case HIGH = 'high'; case NORMAL = 'normal'; case LOW = 'low'; public static function tryFromString(string $value): self { if (! self::isValid($value)) { throw new InvalidArgumentException( sprintf('Invalid queue priority \"%s\" selected', $value) ); } return self::tryFrom($value); } public static function isValid(string $value): bool { return self::tryFrom($value) !== null; } public function isLow(): bool { return $this === self::LOW; } public function isHigh(): bool { return $this === self::HIGH; } } app/Component/ES/UpdateProcessManager.php +12-9Lines changed: 12 additions & 9 deletions Original file line numberOriginal file lineDiff line numberDiff line change if ($selectionList->isEmpty()) { if ($selectionList->isEmpty()) { return false; return false; } } /** /** * A stale chunk will always be smaller than a regular chunk. * A stale chunk will always be smaller than a regular chunk. * That doesn't mean there aren't any other scheduled entities for processing * That doesn't mean there aren't any other scheduled entities for processing private function rescheduleThrottledEntities(SelectionList $selectionList): void private function rescheduleThrottledEntities(SelectionList $selectionList): void { { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $groups = $selectionList->getEntityListGroups(); $this->updateTarget, foreach ($groups as $eachGroup) { $selectionList->getNormalPriorityEntityId() $groupEntityIds = $selectionList->getEntityListItemsByGroup($eachGroup); ); if (! empty($groupEntityIds)) { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $this->updateTarget, entityType: $this->updateTarget, $selectionList->getHighPriorityEntityIds(), entityIds: $groupEntityIds, true priority: QueuePriorityEnum::tryFromString($eachGroup) ); ); } } } } } } app/Console/Commands/Elasticsearch/AsyncUpdateEsEntities.php +9-3Lines changed: 9 additions & 3 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Illuminate\\Support\\Str; use Illuminate\\Support\\Str; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Component\\ES\\UpdateProcessManager; use Jiminny\\Component\\ES\\UpdateProcessManager; use Jiminny\\Exceptions\\InvalidArgumentException; use Jiminny\\Exceptions\\InvalidArgumentException; use Jiminny\\Traits\\GracefullyStoppable; use Jiminny\\Traits\\GracefullyStoppable; Redis::set($gaugeLockName, true); Redis::set($gaugeLockName, true); Redis::expire($gaugeLockName, 60); Redis::expire($gaugeLockName, 60); $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::HIGH), ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update', $updateTarget), stat: sprintf('jiminny.%s-for-update', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::NORMAL), ); ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), stat: sprintf('jiminny.%s-for-update-low', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, true), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::LOW), ); ); } } app/Console/Commands/Elasticsearch/ResetAsyncElasticSearchCommand.php +5-1Lines changed: 5 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder; use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder; use Jiminny\\Component\\ES\\Processor\\Traits\\ValidateUpdateTargetTrait; use Jiminny\\Component\\ES\\Processor\\Traits\\ValidateUpdateTargetTrait; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Component\\ES\\Repositories\\EsResetRepositoryInterface; use Jiminny\\Component\\ES\\Repositories\\EsResetRepositoryInterface; use Jiminny\\Exceptions\\InvalidArgumentException; use Jiminny\\Exceptions\\InvalidArgumentException; use Jiminny\\Traits\\GracefullyStoppable; use Jiminny\\Traits\\GracefullyStoppable; private function getRemainingScheduledEntities(bool $printStatus = false): int private function getRemainingScheduledEntities(bool $printStatus = false): int { { $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget, true); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount( $this->updateTarget, QueuePriorityEnum::HIGH ); if ($printStatus) { if ($printStatus) { $this->line( $this->line(","depth":21,"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"You said","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app/Component/ES/Listeners/UpdateMultipleTargetsListener.php","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"+2-1Lines changed: 2 additions & 1 deletion","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\\Component\\ES\\Listeners;","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"namespace Jiminny\\Component\\ES\\Listeners;","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch;","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch;","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\QueuePriorityEnum;","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Contracts\\ES\\Events\\UpdateMultipleEntities;","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Contracts\\ES\\Events\\UpdateMultipleEntities;","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Psr\\Log\\LoggerInterface;","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Psr\\Log\\LoggerInterface;","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getUpdateTargetValue(),","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getUpdateTargetValue(),","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getEntities(),","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getEntities(),","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->isPriority()","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL,","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":");","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":");","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app/Component/ES/Listeners/UpdateSingleTargetListener.php","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"+9-1Lines changed: 9 additions & 1 deletion","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Actions\\TrackElasticSearchOperations;","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Actions\\TrackElasticSearchOperations;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\QueuePriorityEnum;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Contracts\\ES\\Events\\UpdateSingleEntity;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Contracts\\ES\\Events\\UpdateSingleEntity;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Psr\\Log\\LoggerInterface;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Psr\\Log\\LoggerInterface;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"'entityId' => $event->getEntityId(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"'entityId' => $event->getEntityId(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"]);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"]);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/**","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* @important:","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* Synchronous event should eventually be deprecated.","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* Instant write operations are blocking and should be used sparingly.","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* It is much better in terms of performance to write 100 or 1000 documents at once,","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* and have one blocking reindex operation, instead of writing 10 documents synchronously.","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"*/","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"if ($event->isSyncEvent()) {","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"if ($event->isSyncEvent()) {","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$this->handleSyncEvent($event);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$this->handleSyncEvent($event);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AsyncUpdateElasticSearch::markEntityForUpdate(","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AsyncUpdateElasticSearch::markEntityForUpdate(","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getUpdateTargetValue(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getUpdateTargetValue(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getEntityId(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getEntityId(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->isPriority()","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL,","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":");","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":");","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app/Component/ES/Processor/Actions/UpsertDocumentsAction.php","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"+2-1Lines changed: 2 additions & 1 deletion","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Processor\\DTOs\\SimpleCollection;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\DTOs\\SimpleCollection;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\ResponseEvaluator;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\ResponseEvaluator;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\QueuePriorityEnum;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Exceptions\\InvalidDataException;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Exceptions\\InvalidDataException;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Sentry\\Laravel\\Facade as Sentry;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Sentry\\Laravel\\Facade as Sentry;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AsyncUpdateElasticSearch::markEntityForUpdate(","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AsyncUpdateElasticSearch::markEntityForUpdate(","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"entityType: $this->updateTarget,","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"entityType: $this->updateTarget,","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"entityId: (int) $document->getId(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"entityId: (int) $document->getId(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"withPriority: true","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"priority: QueuePriorityEnum::HIGH,","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":");","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":");","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app/Component/ES/Processor/DTOs/SelectionList.php","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"+54-17Lines changed: 54 additions & 17 deletions","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Original file line numberOriginal file lineDiff line numberDiff line change","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"namespace Jiminny\\Component\\ES\\Processor\\DTOs;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"namespace Jiminny\\Component\\ES\\Processor\\DTOs;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\QueuePriorityEnum;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/**","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/**","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* A very basic and simple collection of entity IDs.","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* A very basic and simple collection of entity IDs.","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"*/","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"*/","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"class SelectionList","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"class SelectionList","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function __construct(","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private const int DEFAULT_CHUNK = 200;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private readonly array $priorityEntityIdList = [],","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private readonly array $normalEntityIdList = [],","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private int $chunkSize = self::DEFAULT_CHUNK;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private readonly bool $isStaleChunkSelected = false,","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private bool $isStaleChunkSelected = false;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private readonly int $chunkSize = 200,","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private array $selectedEntityIds = [];","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":") {","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"// Do nothing","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function setChunkSize(int $chunkSize): void","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$this->chunkSize = $chunkSize;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function getAllIds(): array","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function markStale(): void","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"return array_merge($this->priorityEntityIdList, $this->normalEntityIdList);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$this->isStaleChunkSelected = true;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function count(): int","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function addEntityList(string|QueuePriorityEnum $priority, array $entityIds): void","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"return count($this->priorityEntityIdList) + count($this->normalEntityIdList);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$priorityKey = $this->normalisePriority($priority);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"if (! array_key_exists($priorityKey, $this->selectedEntityIds)) {","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$this->selectedEntityIds[$priorityKey] = [];","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$this->selectedEntityIds[$priorityKey] = array_merge($this->selectedEntityIds[$priorityKey], $entityIds);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function isEmpty(): bool","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/**","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* @return string[]","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"*/","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function getEntityListGroups(): array","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"return empty($this->priorityEntityIdList) && empty($this->normalEntityIdList);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"return array_keys($this->selectedEntityIds);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function getHighPriorityEntityIds(): array","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function getEntityListItemsByGroup(string|QueuePriorityEnum $priority): array","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"return $this->priorityEntityIdList;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$priorityKey = $this->normalisePriority($priority);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"return $this->selectedEntityIds[$priorityKey] ?? [];","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function getNormalPriorityEntityId(): array","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function getAllIds(): array","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"return $this->normalEntityIdList;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$allIds = [];","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"foreach ($this->selectedEntityIds as $entityIds) {","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$allIds = array_merge($allIds, $entityIds);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"return $allIds;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function count(): int","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"return array_sum(","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"array_map('count', $this->selectedEntityIds)","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":");","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function isEmpty(): bool","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"return $this->count() === 0;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function isStaleChunkSelected(): bool","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"}]...
|
3856218954502019449
|
-1144453838252598132
|
click
|
accessibility
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
Close tab
New Tab
Customize sidebar
Close Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
AI Chat settings
Close
WORK, Google Account: [EMAIL]
Main menu
New chat
Gemini
New Chat
Open menu for conversation actions.
Conversation with Gemini
Conversation with Gemini
Show the uploaded image in a lightbox
Copy prompt
You said Make a PR of changes Find potential issues and bottlenecks
You said
Make a PR of changes Find potential issues and bottlenecks
Listen
Show thinking
Gemini said
Gemini said
I can see you've uploaded a screenshot of a code diff, likely from a version control system given the red and green highlights. I would love to help you review the changes, spot bottlenecks, and help you draft a Pull Request.
However,
the image resolution is far too low for me to read.
It appears to be a completely zoomed-out view where the code has been reduced to tiny, illegible pixels. Because of this, I cannot extract any text or logic to analyze.
How You Can Share the Code
How You Can Share the Code
To help me review your code effectively, please try one of the following:
Paste the text directly:
Copy the specific code blocks (both the old and new versions if possible) and paste them directly into our chat.
Upload the files:
If the changes are extensive, you can upload the raw text or code files.
Take high-resolution screenshots:
If you must use images, take closer, readable screenshots of the specific functions or methods you want me to review.
Once you provide the readable code, I can dive right in to identify potential bugs, assess performance bottlenecks, and help you summarize the changes for your PR!
Good response
Bad response
Share & export
Copy
Show more options
Copy prompt
Edit
You said app/Component/ES/Listeners/UpdateMultipleTargetsListener.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\Component\ES\Listeners; namespace Jiminny\Component\ES\Listeners; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Contracts\ES\Events\UpdateMultipleEntities; use Jiminny\Contracts\ES\Events\UpdateMultipleEntities; use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface; AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntities(), $event->getEntities(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } } } app/Component/ES/Listeners/UpdateSingleTargetListener.php +9-1Lines changed: 9 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Actions\TrackElasticSearchOperations; use Jiminny\Component\ES\Actions\TrackElasticSearchOperations; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Contracts\ES\Events\UpdateSingleEntity; use Jiminny\Contracts\ES\Events\UpdateSingleEntity; use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface; 'entityId' => $event->getEntityId(), 'entityId' => $event->getEntityId(), ]); ]); /** * @important: * Synchronous event should eventually be deprecated. * Instant write operations are blocking and should be used sparingly. * It is much better in terms of performance to write 100 or 1000 documents at once, * and have one blocking reindex operation, instead of writing 10 documents synchronously. */ if ($event->isSyncEvent()) { if ($event->isSyncEvent()) { $this->handleSyncEvent($event); $this->handleSyncEvent($event); AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntityId(), $event->getEntityId(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } app/Component/ES/Processor/Actions/UpsertDocumentsAction.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SimpleCollection; use Jiminny\Component\ES\Processor\DTOs\SimpleCollection; use Jiminny\Component\ES\Processor\ResponseEvaluator; use Jiminny\Component\ES\Processor\ResponseEvaluator; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Exceptions\InvalidDataException; use Jiminny\Exceptions\InvalidDataException; use Sentry\Laravel\Facade as Sentry; use Sentry\Laravel\Facade as Sentry; AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( entityType: $this->updateTarget, entityType: $this->updateTarget, entityId: (int) $document->getId(), entityId: (int) $document->getId(), withPriority: true priority: QueuePriorityEnum::HIGH, ); ); } } app/Component/ES/Processor/DTOs/SelectionList.php +54-17Lines changed: 54 additions & 17 deletions Original file line numberOriginal file lineDiff line numberDiff line change namespace Jiminny\Component\ES\Processor\DTOs; namespace Jiminny\Component\ES\Processor\DTOs; use Jiminny\Component\ES\QueuePriorityEnum; /** /** * A very basic and simple collection of entity IDs. * A very basic and simple collection of entity IDs. */ */ class SelectionList class SelectionList { { public function __construct( private const int DEFAULT_CHUNK = 200; private readonly array $priorityEntityIdList = [], private readonly array $normalEntityIdList = [], private int $chunkSize = self::DEFAULT_CHUNK; private readonly bool $isStaleChunkSelected = false, private bool $isStaleChunkSelected = false; private readonly int $chunkSize = 200, private array $selectedEntityIds = []; ) { // Do nothing public function setChunkSize(int $chunkSize): void { $this->chunkSize = $chunkSize; } } public function getAllIds(): array public function markStale(): void { { return array_merge($this->priorityEntityIdList, $this->normalEntityIdList); $this->isStaleChunkSelected = true; } } public function count(): int public function addEntityList(string|QueuePriorityEnum $priority, array $entityIds): void { { return count($this->priorityEntityIdList) + count($this->normalEntityIdList); $priorityKey = $this->normalisePriority($priority); if (! array_key_exists($priorityKey, $this->selectedEntityIds)) { $this->selectedEntityIds[$priorityKey] = []; } $this->selectedEntityIds[$priorityKey] = array_merge($this->selectedEntityIds[$priorityKey], $entityIds); } } public function isEmpty(): bool /** * @return string[] */ public function getEntityListGroups(): array { { return empty($this->priorityEntityIdList) && empty($this->normalEntityIdList); return array_keys($this->selectedEntityIds); } } public function getHighPriorityEntityIds(): array public function getEntityListItemsByGroup(string|QueuePriorityEnum $priority): array { { return $this->priorityEntityIdList; $priorityKey = $this->normalisePriority($priority); return $this->selectedEntityIds[$priorityKey] ?? []; } } public function getNormalPriorityEntityId(): array public function getAllIds(): array { { return $this->normalEntityIdList; $allIds = []; foreach ($this->selectedEntityIds as $entityIds) { $allIds = array_merge($allIds, $entityIds); } return $allIds; } public function count(): int { return array_sum( array_map('count', $this->selectedEntityIds) ); } public function isEmpty(): bool { return $this->count() === 0; } } public function isStaleChunkSelected(): bool public function isStaleChunkSelected(): bool { { return $this->count() >= $this->chunkSize; return $this->count() >= $this->chunkSize; } } private function normalisePriority(string|QueuePriorityEnum $priority): string { return $priority instanceof QueuePriorityEnum ? $priority->value : $priority; } } } app/Component/ES/Processor/Traits/SelectEntityListTrait.php +27-4Lines changed: 27 additions & 4 deletions Original file line numberOriginal file lineDiff line numberDiff line change use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; /** /** * Build the correct source list name for the type of entity and priority * Build the correct source list name for the type of entity and priority */ */ trait SelectEntityListTrait trait SelectEntityListTrait { { /** * Highest priority queue for data requiring near-instant availability. * Very few entities should be added here, only when absolutely necessary. */ private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; /** * Normal priority queue for normal application operations. * Almost all update events should pass through this queue */ private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; protected static function selectTargetList(string $entityType, bool $withPriority = false): string /** { * Nonblocking low priority queue. This queue will be consumed only when there is nothing * with higher priority. * * This queue will be used for operations such as es:reset-async */ private const string ENTITIES_LOW_PRIORITIES_LIST = '%s-for-update-low'; protected static function selectTargetList( string $entityType, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { if (! in_array($entityType, UpdateTarget::allowedTargets())) { if (! in_array($entityType, UpdateTarget::allowedTargets())) { throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); } } if ($withPriority) { if ($priority->isHigh()) { Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); } } if ($priority->isLow()) { return sprintf(self::ENTITIES_LOW_PRIORITIES_LIST, $entityType); } return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); } } } } app/Component/ES/Processor/TargetEntitiesSelector.php +26-21Lines changed: 26 additions & 21 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SelectionList; use Jiminny\Component\ES\Processor\DTOs\SelectionList; use Jiminny\Component\ES\Processor\Traits\ExtractIdsTrait; use Jiminny\Component\ES\Processor\Traits\ExtractIdsTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\QueuePriorityEnum; /** /** * This class supplies a list of entities pending an update. * This class supplies a list of entities pending an update. public function select(): SelectionList public function select(): SelectionList { { $staleWorkEntityIds = $this->getStaleChunk(); $selectionList = new SelectionList(); $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $staleWorkEntityIds = $this->getStaleChunk(); if (count($staleWorkEntityIds) > 0) { if (count($staleWorkEntityIds) > 0) { return new SelectionList( /** priorityEntityIdList: $staleWorkEntityIds, * Stale chunks are treated as high priority isStaleChunkSelected: true, */ chunkSize: ChunkSize::getStaleChunkSize($this->updateTarget), $selectionList->markStale(); ); $selectionList->addEntityList(QueuePriorityEnum::HIGH, $staleWorkEntityIds); $selectionList->setChunkSize(ChunkSize::getStaleChunkSize($this->updateTarget)); return $selectionList; } } $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $selectionList->setChunkSize($mainChunkSize); $priorityEntityIdsList = $this->extractIdsFromSet( $priorityEntityIdsList = $this->extractIds(QueuePriorityEnum::HIGH, $mainChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, true), $selectionList->addEntityList(QueuePriorityEnum::HIGH, $priorityEntityIdsList); $mainChunkSize, ); $normalEntityIdsList = []; $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); if ($normalEntityChunkSize > 0) { if ($normalEntityChunkSize > 0) { $normalEntityIdsList = $this->extractIdsFromSet( $normalEntityIdsList = $this->extractIds(QueuePriorityEnum::NORMAL, $normalEntityChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, false), $selectionList->addEntityList(QueuePriorityEnum::NORMAL, $normalEntityIdsList); $normalEntityChunkSize ); } } return new SelectionList( return $selectionList; priorityEntityIdList: $priorityEntityIdsList, normalEntityIdList: $normalEntityIdsList, chunkSize: $mainChunkSize ); } } private function getStaleChunk(): array private function getStaleChunk(): array return []; return []; } } private function extractIds(QueuePriorityEnum $priority, int $chunkSize): array { return $this->extractIdsFromSet( AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, $priority), $chunkSize ); } } } app/Component/ES/AsyncUpdateElasticSearch.php +17-10Lines changed: 17 additions & 10 deletions Original file line numberOriginal file lineDiff line numberDiff line change * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * and other activity related data * and other activity related data */ */ public static function markEntityForUpdate(string $entityType, int $entityId, bool $withPriority = false): void public static function markEntityForUpdate( { string $entityType, $targetList = self::selectTargetList($entityType, $withPriority); int $entityId, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { $targetList = self::selectTargetList($entityType, $priority); Redis::sadd($targetList, $entityId); Redis::sadd($targetList, $entityId); Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ 'entityType' => $entityType, 'entityType' => $entityType, 'entityId' => $entityId, 'entityId' => $entityId, 'collectionKey' => $targetList, 'collectionKey' => $targetList, 'withPriority' => $withPriority, 'priority' => $priority->value, ]); ]); } } public static function bulkMarkEntitiesForUpdate( public static function bulkMarkEntitiesForUpdate( string $entityType, string $entityType, array $entityIds, array $entityIds, bool $withPriority = false QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { ): void { if (empty($entityIds)) { if (empty($entityIds)) { return; return; } } $targetList = self::selectTargetList($entityType, $withPriority); $targetList = self::selectTargetList($entityType, $priority); Redis::saddarray($targetList, $entityIds); Redis::saddarray($targetList, $entityIds); } } * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Takes priority into consideration. * Takes priority into consideration. */ */ public static function getEntitiesSourceList(string $updateTarget, $priority = false): string public static function getEntitiesSourceList( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { return self::selectTargetList($updateTarget, $priority); return self::selectTargetList($updateTarget, $priority); } } /** /** * Externally called helper methods * Externally called helper methods * - count and flush * - count and flush */ */ public static function getEntitiesListCount(string $updateTarget, $priority = false): int public static function getEntitiesListCount( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): int { $targetList = self::selectTargetList($updateTarget, $priority); $targetList = self::selectTargetList($updateTarget, $priority); return Redis::scard($targetList); return Redis::scard($targetList); app/Component/ES/QueuePriorityEnum.php +40Lines changed: 40 additions & 0 deletions Original file line numberOriginal file lineDiff line numberDiff line change <?php declare(strict_types=1); namespace Jiminny\Component\ES; use Jiminny\Exceptions\InvalidArgumentException; enum QueuePriorityEnum: string { case HIGH = 'high'; case NORMAL = 'normal'; case LOW = 'low'; public static function tryFromString(string $value): self { if (! self::isValid($value)) { throw new InvalidArgumentException( sprintf('Invalid queue priority "%s" selected', $value) ); } return self::tryFrom($value); } public static function isValid(string $value): bool { return self::tryFrom($value) !== null; } public function isLow(): bool { return $this === self::LOW; } public function isHigh(): bool { return $this === self::HIGH; } } app/Component/ES/UpdateProcessManager.php +12-9Lines changed: 12 additions & 9 deletions Original file line numberOriginal file lineDiff line numberDiff line change if ($selectionList->isEmpty()) { if ($selectionList->isEmpty()) { return false; return false; } } /** /** * A stale chunk will always be smaller than a regular chunk. * A stale chunk will always be smaller than a regular chunk. * That doesn't mean there aren't any other scheduled entities for processing * That doesn't mean there aren't any other scheduled entities for processing private function rescheduleThrottledEntities(SelectionList $selectionList): void private function rescheduleThrottledEntities(SelectionList $selectionList): void { { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $groups = $selectionList->getEntityListGroups(); $this->updateTarget, foreach ($groups as $eachGroup) { $selectionList->getNormalPriorityEntityId() $groupEntityIds = $selectionList->getEntityListItemsByGroup($eachGroup); ); if (! empty($groupEntityIds)) { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $this->updateTarget, entityType: $this->updateTarget, $selectionList->getHighPriorityEntityIds(), entityIds: $groupEntityIds, true priority: QueuePriorityEnum::tryFromString($eachGroup) ); ); } } } } } } app/Console/Commands/Elasticsearch/AsyncUpdateEsEntities.php +9-3Lines changed: 9 additions & 3 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Illuminate\Support\Str; use Illuminate\Support\Str; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Component\ES\UpdateProcessManager; use Jiminny\Component\ES\UpdateProcessManager; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Traits\GracefullyStoppable; use Jiminny\Traits\GracefullyStoppable; Redis::set($gaugeLockName, true); Redis::set($gaugeLockName, true); Redis::expire($gaugeLockName, 60); Redis::expire($gaugeLockName, 60); $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::HIGH), ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update', $updateTarget), stat: sprintf('jiminny.%s-for-update', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::NORMAL), ); ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), stat: sprintf('jiminny.%s-for-update-low', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, true), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::LOW), ); ); } } app/Console/Commands/Elasticsearch/ResetAsyncElasticSearchCommand.php +5-1Lines changed: 5 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\Traits\ValidateUpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\ValidateUpdateTargetTrait; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Component\ES\Repositories\EsResetRepositoryInterface; use Jiminny\Component\ES\Repositories\EsResetRepositoryInterface; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Traits\GracefullyStoppable; use Jiminny\Traits\GracefullyStoppable; private function getRemainingScheduledEntities(bool $printStatus = false): int private function getRemainingScheduledEntities(bool $printStatus = false): int { { $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget, true); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount( $this->updateTarget, QueuePriorityEnum::HIGH ); if ($printStatus) { if ($printStatus) { $this->line( $this->line(
You said
app/Component/ES/Listeners/UpdateMultipleTargetsListener.php
+2-1Lines changed: 2 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\Component\ES\Listeners;
namespace Jiminny\Component\ES\Listeners;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\QueuePriorityEnum;
use Jiminny\Contracts\ES\Events\UpdateMultipleEntities;
use Jiminny\Contracts\ES\Events\UpdateMultipleEntities;
use Psr\Log\LoggerInterface;
use Psr\Log\LoggerInterface;
AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(
AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(
$event->getUpdateTargetValue(),
$event->getUpdateTargetValue(),
$event->getEntities(),
$event->getEntities(),
$event->isPriority()
$event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL,
);
);
}
}
}
}
app/Component/ES/Listeners/UpdateSingleTargetListener.php
+9-1Lines changed: 9 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Actions\TrackElasticSearchOperations;
use Jiminny\Component\ES\Actions\TrackElasticSearchOperations;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\Processor\EntityQueryBuilder;
use Jiminny\Component\ES\Processor\EntityQueryBuilder;
use Jiminny\Component\ES\QueuePriorityEnum;
use Jiminny\Contracts\ES\Events\UpdateSingleEntity;
use Jiminny\Contracts\ES\Events\UpdateSingleEntity;
use Psr\Log\LoggerInterface;
use Psr\Log\LoggerInterface;
'entityId' => $event->getEntityId(),
'entityId' => $event->getEntityId(),
]);
]);
/**
* @important:
* Synchronous event should eventually be deprecated.
* Instant write operations are blocking and should be used sparingly.
* It is much better in terms of performance to write 100 or 1000 documents at once,
* and have one blocking reindex operation, instead of writing 10 documents synchronously.
*/
if ($event->isSyncEvent()) {
if ($event->isSyncEvent()) {
$this->handleSyncEvent($event);
$this->handleSyncEvent($event);
AsyncUpdateElasticSearch::markEntityForUpdate(
AsyncUpdateElasticSearch::markEntityForUpdate(
$event->getUpdateTargetValue(),
$event->getUpdateTargetValue(),
$event->getEntityId(),
$event->getEntityId(),
$event->isPriority()
$event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL,
);
);
}
}
app/Component/ES/Processor/Actions/UpsertDocumentsAction.php
+2-1Lines changed: 2 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SimpleCollection;
use Jiminny\Component\ES\Processor\DTOs\SimpleCollection;
use Jiminny\Component\ES\Processor\ResponseEvaluator;
use Jiminny\Component\ES\Processor\ResponseEvaluator;
use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait;
use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait;
use Jiminny\Component\ES\QueuePriorityEnum;
use Jiminny\Exceptions\InvalidDataException;
use Jiminny\Exceptions\InvalidDataException;
use Sentry\Laravel\Facade as Sentry;
use Sentry\Laravel\Facade as Sentry;
AsyncUpdateElasticSearch::markEntityForUpdate(
AsyncUpdateElasticSearch::markEntityForUpdate(
entityType: $this->updateTarget,
entityType: $this->updateTarget,
entityId: (int) $document->getId(),
entityId: (int) $document->getId(),
withPriority: true
priority: QueuePriorityEnum::HIGH,
);
);
}
}
app/Component/ES/Processor/DTOs/SelectionList.php
+54-17Lines changed: 54 additions & 17 deletions
Original file line numberOriginal file lineDiff line numberDiff line change
namespace Jiminny\Component\ES\Processor\DTOs;
namespace Jiminny\Component\ES\Processor\DTOs;
use Jiminny\Component\ES\QueuePriorityEnum;
/**
/**
* A very basic and simple collection of entity IDs.
* A very basic and simple collection of entity IDs.
*/
*/
class SelectionList
class SelectionList
{
{
public function __construct(
private const int DEFAULT_CHUNK = 200;
private readonly array $priorityEntityIdList = [],
private readonly array $normalEntityIdList = [],
private int $chunkSize = self::DEFAULT_CHUNK;
private readonly bool $isStaleChunkSelected = false,
private bool $isStaleChunkSelected = false;
private readonly int $chunkSize = 200,
private array $selectedEntityIds = [];
) {
// Do nothing
public function setChunkSize(int $chunkSize): void
{
$this->chunkSize = $chunkSize;
}
}
public function getAllIds(): array
public function markStale(): void
{
{
return array_merge($this->priorityEntityIdList, $this->normalEntityIdList);
$this->isStaleChunkSelected = true;
}
}
public function count(): int
public function addEntityList(string|QueuePriorityEnum $priority, array $entityIds): void
{
{
return count($this->priorityEntityIdList) + count($this->normalEntityIdList);
$priorityKey = $this->normalisePriority($priority);
if (! array_key_exists($priorityKey, $this->selectedEntityIds)) {
$this->selectedEntityIds[$priorityKey] = [];
}
$this->selectedEntityIds[$priorityKey] = array_merge($this->selectedEntityIds[$priorityKey], $entityIds);
}
}
public function isEmpty(): bool
/**
* @return string[]
*/
public function getEntityListGroups(): array
{
{
return empty($this->priorityEntityIdList) && empty($this->normalEntityIdList);
return array_keys($this->selectedEntityIds);
}
}
public function getHighPriorityEntityIds(): array
public function getEntityListItemsByGroup(string|QueuePriorityEnum $priority): array
{
{
return $this->priorityEntityIdList;
$priorityKey = $this->normalisePriority($priority);
return $this->selectedEntityIds[$priorityKey] ?? [];
}
}
public function getNormalPriorityEntityId(): array
public function getAllIds(): array
{
{
return $this->normalEntityIdList;
$allIds = [];
foreach ($this->selectedEntityIds as $entityIds) {
$allIds = array_merge($allIds, $entityIds);
}
return $allIds;
}
public function count(): int
{
return array_sum(
array_map('count', $this->selectedEntityIds)
);
}
public function isEmpty(): bool
{
return $this->count() === 0;
}
}
public function isStaleChunkSelected(): bool...
|
55690
|
NULL
|
NULL
|
NULL
|
|
55693
|
1933
|
19
|
2026-05-19T06:41:11.572072+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779172871572_m2.jpg...
|
Firefox
|
JY-20808 low priority indexing queue by Vasil-Jimi JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app — Work...
|
1
|
github.com/jiminny/app/pull/12082/changes#diff-eea github.com/jiminny/app/pull/12082/changes#diff-eeacd403a912dc6a384056b3fd5356e90255c2794f5665a40bbda5c683098397...
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
Close tab
New Tab
Customize sidebar
Close Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
AI Chat settings
Close
WORK, Google Account: [EMAIL]
Main menu
New chat
Gemini
New Chat
Open menu for conversation actions.
Conversation with Gemini
Conversation with Gemini
Show the uploaded image in a lightbox
Copy prompt
You said Make a PR of changes Find potential issues and bottlenecks
You said
Make a PR of changes Find potential issues and bottlenecks
Listen
Show thinking
Gemini said
Gemini said
I can see you've uploaded a screenshot of a code diff, likely from a version control system given the red and green highlights. I would love to help you review the changes, spot bottlenecks, and help you draft a Pull Request.
However,
the image resolution is far too low for me to read.
It appears to be a completely zoomed-out view where the code has been reduced to tiny, illegible pixels. Because of this, I cannot extract any text or logic to analyze.
How You Can Share the Code
How You Can Share the Code
To help me review your code effectively, please try one of the following:
Paste the text directly:
Copy the specific code blocks (both the old and new versions if possible) and paste them directly into our chat.
Upload the files:
If the changes are extensive, you can upload the raw text or code files.
Take high-resolution screenshots:
If you must use images, take closer, readable screenshots of the specific functions or methods you want me to review.
Once you provide the readable code, I can dive right in to identify potential bugs, assess performance bottlenecks, and help you summarize the changes for your PR!
Good response
Bad response
Share & export
Copy
Show more options
Copy prompt
Edit
You said app/Component/ES/Listeners/UpdateMultipleTargetsListener.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\Component\ES\Listeners; namespace Jiminny\Component\ES\Listeners; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Contracts\ES\Events\UpdateMultipleEntities; use Jiminny\Contracts\ES\Events\UpdateMultipleEntities; use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface; AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntities(), $event->getEntities(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } } } app/Component/ES/Listeners/UpdateSingleTargetListener.php +9-1Lines changed: 9 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Actions\TrackElasticSearchOperations; use Jiminny\Component\ES\Actions\TrackElasticSearchOperations; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Contracts\ES\Events\UpdateSingleEntity; use Jiminny\Contracts\ES\Events\UpdateSingleEntity; use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface; 'entityId' => $event->getEntityId(), 'entityId' => $event->getEntityId(), ]); ]); /** * @important: * Synchronous event should eventually be deprecated. * Instant write operations are blocking and should be used sparingly. * It is much better in terms of performance to write 100 or 1000 documents at once, * and have one blocking reindex operation, instead of writing 10 documents synchronously. */ if ($event->isSyncEvent()) { if ($event->isSyncEvent()) { $this->handleSyncEvent($event); $this->handleSyncEvent($event); AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntityId(), $event->getEntityId(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } app/Component/ES/Processor/Actions/UpsertDocumentsAction.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SimpleCollection; use Jiminny\Component\ES\Processor\DTOs\SimpleCollection; use Jiminny\Component\ES\Processor\ResponseEvaluator; use Jiminny\Component\ES\Processor\ResponseEvaluator; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Exceptions\InvalidDataException; use Jiminny\Exceptions\InvalidDataException; use Sentry\Laravel\Facade as Sentry; use Sentry\Laravel\Facade as Sentry; AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( entityType: $this->updateTarget, entityType: $this->updateTarget, entityId: (int) $document->getId(), entityId: (int) $document->getId(), withPriority: true priority: QueuePriorityEnum::HIGH, ); ); } } app/Component/ES/Processor/DTOs/SelectionList.php +54-17Lines changed: 54 additions & 17 deletions Original file line numberOriginal file lineDiff line numberDiff line change namespace Jiminny\Component\ES\Processor\DTOs; namespace Jiminny\Component\ES\Processor\DTOs; use Jiminny\Component\ES\QueuePriorityEnum; /** /** * A very basic and simple collection of entity IDs. * A very basic and simple collection of entity IDs. */ */ class SelectionList class SelectionList { { public function __construct( private const int DEFAULT_CHUNK = 200; private readonly array $priorityEntityIdList = [], private readonly array $normalEntityIdList = [], private int $chunkSize = self::DEFAULT_CHUNK; private readonly bool $isStaleChunkSelected = false, private bool $isStaleChunkSelected = false; private readonly int $chunkSize = 200, private array $selectedEntityIds = []; ) { // Do nothing public function setChunkSize(int $chunkSize): void { $this->chunkSize = $chunkSize; } } public function getAllIds(): array public function markStale(): void { { return array_merge($this->priorityEntityIdList, $this->normalEntityIdList); $this->isStaleChunkSelected = true; } } public function count(): int public function addEntityList(string|QueuePriorityEnum $priority, array $entityIds): void { { return count($this->priorityEntityIdList) + count($this->normalEntityIdList); $priorityKey = $this->normalisePriority($priority); if (! array_key_exists($priorityKey, $this->selectedEntityIds)) { $this->selectedEntityIds[$priorityKey] = []; } $this->selectedEntityIds[$priorityKey] = array_merge($this->selectedEntityIds[$priorityKey], $entityIds); } } public function isEmpty(): bool /** * @return string[] */ public function getEntityListGroups(): array { { return empty($this->priorityEntityIdList) && empty($this->normalEntityIdList); return array_keys($this->selectedEntityIds); } } public function getHighPriorityEntityIds(): array public function getEntityListItemsByGroup(string|QueuePriorityEnum $priority): array { { return $this->priorityEntityIdList; $priorityKey = $this->normalisePriority($priority); return $this->selectedEntityIds[$priorityKey] ?? []; } } public function getNormalPriorityEntityId(): array public function getAllIds(): array { { return $this->normalEntityIdList; $allIds = []; foreach ($this->selectedEntityIds as $entityIds) { $allIds = array_merge($allIds, $entityIds); } return $allIds; } public function count(): int { return array_sum( array_map('count', $this->selectedEntityIds) ); } public function isEmpty(): bool { return $this->count() === 0; } } public function isStaleChunkSelected(): bool public function isStaleChunkSelected(): bool { { return $this->count() >= $this->chunkSize; return $this->count() >= $this->chunkSize; } } private function normalisePriority(string|QueuePriorityEnum $priority): string { return $priority instanceof QueuePriorityEnum ? $priority->value : $priority; } } } app/Component/ES/Processor/Traits/SelectEntityListTrait.php +27-4Lines changed: 27 additions & 4 deletions Original file line numberOriginal file lineDiff line numberDiff line change use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; /** /** * Build the correct source list name for the type of entity and priority * Build the correct source list name for the type of entity and priority */ */ trait SelectEntityListTrait trait SelectEntityListTrait { { /** * Highest priority queue for data requiring near-instant availability. * Very few entities should be added here, only when absolutely necessary. */ private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; /** * Normal priority queue for normal application operations. * Almost all update events should pass through this queue */ private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; protected static function selectTargetList(string $entityType, bool $withPriority = false): string /** { * Nonblocking low priority queue. This queue will be consumed only when there is nothing * with higher priority. * * This queue will be used for operations such as es:reset-async */ private const string ENTITIES_LOW_PRIORITIES_LIST = '%s-for-update-low'; protected static function selectTargetList( string $entityType, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { if (! in_array($entityType, UpdateTarget::allowedTargets())) { if (! in_array($entityType, UpdateTarget::allowedTargets())) { throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); } } if ($withPriority) { if ($priority->isHigh()) { Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); } } if ($priority->isLow()) { return sprintf(self::ENTITIES_LOW_PRIORITIES_LIST, $entityType); } return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); } } } } app/Component/ES/Processor/TargetEntitiesSelector.php +26-21Lines changed: 26 additions & 21 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SelectionList; use Jiminny\Component\ES\Processor\DTOs\SelectionList; use Jiminny\Component\ES\Processor\Traits\ExtractIdsTrait; use Jiminny\Component\ES\Processor\Traits\ExtractIdsTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\QueuePriorityEnum; /** /** * This class supplies a list of entities pending an update. * This class supplies a list of entities pending an update. public function select(): SelectionList public function select(): SelectionList { { $staleWorkEntityIds = $this->getStaleChunk(); $selectionList = new SelectionList(); $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $staleWorkEntityIds = $this->getStaleChunk(); if (count($staleWorkEntityIds) > 0) { if (count($staleWorkEntityIds) > 0) { return new SelectionList( /** priorityEntityIdList: $staleWorkEntityIds, * Stale chunks are treated as high priority isStaleChunkSelected: true, */ chunkSize: ChunkSize::getStaleChunkSize($this->updateTarget), $selectionList->markStale(); ); $selectionList->addEntityList(QueuePriorityEnum::HIGH, $staleWorkEntityIds); $selectionList->setChunkSize(ChunkSize::getStaleChunkSize($this->updateTarget)); return $selectionList; } } $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $selectionList->setChunkSize($mainChunkSize); $priorityEntityIdsList = $this->extractIdsFromSet( $priorityEntityIdsList = $this->extractIds(QueuePriorityEnum::HIGH, $mainChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, true), $selectionList->addEntityList(QueuePriorityEnum::HIGH, $priorityEntityIdsList); $mainChunkSize, ); $normalEntityIdsList = []; $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); if ($normalEntityChunkSize > 0) { if ($normalEntityChunkSize > 0) { $normalEntityIdsList = $this->extractIdsFromSet( $normalEntityIdsList = $this->extractIds(QueuePriorityEnum::NORMAL, $normalEntityChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, false), $selectionList->addEntityList(QueuePriorityEnum::NORMAL, $normalEntityIdsList); $normalEntityChunkSize ); } } return new SelectionList( return $selectionList; priorityEntityIdList: $priorityEntityIdsList, normalEntityIdList: $normalEntityIdsList, chunkSize: $mainChunkSize ); } } private function getStaleChunk(): array private function getStaleChunk(): array return []; return []; } } private function extractIds(QueuePriorityEnum $priority, int $chunkSize): array { return $this->extractIdsFromSet( AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, $priority), $chunkSize ); } } } app/Component/ES/AsyncUpdateElasticSearch.php +17-10Lines changed: 17 additions & 10 deletions Original file line numberOriginal file lineDiff line numberDiff line change * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * and other activity related data * and other activity related data */ */ public static function markEntityForUpdate(string $entityType, int $entityId, bool $withPriority = false): void public static function markEntityForUpdate( { string $entityType, $targetList = self::selectTargetList($entityType, $withPriority); int $entityId, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { $targetList = self::selectTargetList($entityType, $priority); Redis::sadd($targetList, $entityId); Redis::sadd($targetList, $entityId); Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ 'entityType' => $entityType, 'entityType' => $entityType, 'entityId' => $entityId, 'entityId' => $entityId, 'collectionKey' => $targetList, 'collectionKey' => $targetList, 'withPriority' => $withPriority, 'priority' => $priority->value, ]); ]); } } public static function bulkMarkEntitiesForUpdate( public static function bulkMarkEntitiesForUpdate( string $entityType, string $entityType, array $entityIds, array $entityIds, bool $withPriority = false QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { ): void { if (empty($entityIds)) { if (empty($entityIds)) { return; return; } } $targetList = self::selectTargetList($entityType, $withPriority); $targetList = self::selectTargetList($entityType, $priority); Redis::saddarray($targetList, $entityIds); Redis::saddarray($targetList, $entityIds); } } * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Takes priority into consideration. * Takes priority into consideration. */ */ public static function getEntitiesSourceList(string $updateTarget, $priority = false): string public static function getEntitiesSourceList( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { return self::selectTargetList($updateTarget, $priority); return self::selectTargetList($updateTarget, $priority); } } /** /** * Externally called helper methods * Externally called helper methods * - count and flush * - count and flush */ */ public static function getEntitiesListCount(string $updateTarget, $priority = false): int public static function getEntitiesListCount( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): int { $targetList = self::selectTargetList($updateTarget, $priority); $targetList = self::selectTargetList($updateTarget, $priority); return Redis::scard($targetList); return Redis::scard($targetList); app/Component/ES/QueuePriorityEnum.php +40Lines changed: 40 additions & 0 deletions Original file line numberOriginal file lineDiff line numberDiff line change <?php declare(strict_types=1); namespace Jiminny\Component\ES; use Jiminny\Exceptions\InvalidArgumentException; enum QueuePriorityEnum: string { case HIGH = 'high'; case NORMAL = 'normal'; case LOW = 'low'; public static function tryFromString(string $value): self { if (! self::isValid($value)) { throw new InvalidArgumentException( sprintf('Invalid queue priority "%s" selected', $value) ); } return self::tryFrom($value); } public static function isValid(string $value): bool { return self::tryFrom($value) !== null; } public function isLow(): bool { return $this === self::LOW; } public function isHigh(): bool { return $this === self::HIGH; } } app/Component/ES/UpdateProcessManager.php +12-9Lines changed: 12 additions & 9 deletions Original file line numberOriginal file lineDiff line numberDiff line change if ($selectionList->isEmpty()) { if ($selectionList->isEmpty()) { return false; return false; } } /** /** * A stale chunk will always be smaller than a regular chunk. * A stale chunk will always be smaller than a regular chunk. * That doesn't mean there aren't any other scheduled entities for processing * That doesn't mean there aren't any other scheduled entities for processing private function rescheduleThrottledEntities(SelectionList $selectionList): void private function rescheduleThrottledEntities(SelectionList $selectionList): void { { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $groups = $selectionList->getEntityListGroups(); $this->updateTarget, foreach ($groups as $eachGroup) { $selectionList->getNormalPriorityEntityId() $groupEntityIds = $selectionList->getEntityListItemsByGroup($eachGroup); ); if (! empty($groupEntityIds)) { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $this->updateTarget, entityType: $this->updateTarget, $selectionList->getHighPriorityEntityIds(), entityIds: $groupEntityIds, true priority: QueuePriorityEnum::tryFromString($eachGroup) ); ); } } } } } } app/Console/Commands/Elasticsearch/AsyncUpdateEsEntities.php +9-3Lines changed: 9 additions & 3 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Illuminate\Support\Str; use Illuminate\Support\Str; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Component\ES\UpdateProcessManager; use Jiminny\Component\ES\UpdateProcessManager; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Traits\GracefullyStoppable; use Jiminny\Traits\GracefullyStoppable; Redis::set($gaugeLockName, true); Redis::set($gaugeLockName, true); Redis::expire($gaugeLockName, 60); Redis::expire($gaugeLockName, 60); $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::HIGH), ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update', $updateTarget), stat: sprintf('jiminny.%s-for-update', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::NORMAL), ); ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), stat: sprintf('jiminny.%s-for-update-low', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, true), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::LOW), ); ); } } app/Console/Commands/Elasticsearch/ResetAsyncElasticSearchCommand.php +5-1Lines changed: 5 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\Traits\ValidateUpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\ValidateUpdateTargetTrait; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Component\ES\Repositories\EsResetRepositoryInterface; use Jiminny\Component\ES\Repositories\EsResetRepositoryInterface; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Traits\GracefullyStoppable; use Jiminny\Traits\GracefullyStoppable; private function getRemainingScheduledEntities(bool $printStatus = false): int private function getRemainingScheduledEntities(bool $printStatus = false): int { { $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget, true); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount( $this->updateTarget, QueuePriorityEnum::HIGH ); if ($printStatus) { if ($printStatus) { $this->line( $this->line(
You said
app/Component/ES/Listeners/UpdateMultipleTargetsListener.php
+2-1Lines changed: 2 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\Component\ES\Listeners;
namespace Jiminny\Component\ES\Listeners;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\QueuePriorityEnum;
use Jiminny\Contracts\ES\Events\UpdateMultipleEntities;
use Jiminny\Contracts\ES\Events\UpdateMultipleEntities;
use Psr\Log\LoggerInterface;
use Psr\Log\LoggerInterface;
AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(
AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(
$event->getUpdateTargetValue(),
$event->getUpdateTargetValue(),
$event->getEntities(),
$event->getEntities(),
$event->isPriority()
$event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL,
);
);
}
}
}
}
app/Component/ES/Listeners/UpdateSingleTargetListener.php
+9-1Lines changed: 9 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Actions\TrackElasticSearchOperations;
use Jiminny\Component\ES\Actions\TrackElasticSearchOperations;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\Processor\EntityQueryBuilder;
use Jiminny\Component\ES\Processor\EntityQueryBuilder;
use Jiminny\Component\ES\QueuePriorityEnum;
use Jiminny\Contracts\ES\Events\UpdateSingleEntity;
use Jiminny\Contracts\ES\Events\UpdateSingleEntity;
use Psr\Log\LoggerInterface;
use Psr\Log\LoggerInterface;
'entityId' => $event->getEntityId(),
'entityId' => $event->getEntityId(),
]);
]);
/**
* @important:
* Synchronous event should eventually be deprecated.
* Instant write operations are blocking and should be used sparingly.
* It is much better in terms of performance to write 100 or 1000 documents at once,
* and have one blocking reindex operation, instead of writing 10 documents synchronously.
*/
if ($event->isSyncEvent()) {
if ($event->isSyncEvent()) {
$this->handleSyncEvent($event);
$this->handleSyncEvent($event);
AsyncUpdateElasticSearch::markEntityForUpdate(
AsyncUpdateElasticSearch::markEntityForUpdate(
$event->getUpdateTargetValue(),
$event->getUpdateTargetValue(),
$event->getEntityId(),
$event->getEntityId(),
$event->isPriority()
$event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL,
);
);
}
}
app/Component/ES/Processor/Actions/UpsertDocumentsAction.php
+2-1Lines changed: 2 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SimpleCollection;
use Jiminny\Component\ES\Processor\DTOs\SimpleCollection;
use Jiminny\Component\ES\Processor\ResponseEvaluator;
use Jiminny\Component\ES\Processor\ResponseEvaluator;
use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait;
use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait;
use Jiminny\Component\ES\QueuePriorityEnum;
use Jiminny\Exceptions\InvalidDataException;
use Jiminny\Exceptions\InvalidDataException;
use Sentry\Laravel\Facade as Sentry;
use Sentry\Laravel\Facade as Sentry;
AsyncUpdateElasticSearch::markEntityForUpdate(
AsyncUpdateElasticSearch::markEntityForUpdate(
entityType: $this->updateTarget,
entityType: $this->updateTarget,
entityId: (int) $document->getId(),
entityId: (int) $document->getId(),
withPriority: true
priority: QueuePriorityEnum::HIGH,
);
);
}
}
app/Component/ES/Processor/DTOs/SelectionList.php
+54-17Lines changed: 54 additions & 17 deletions
Original file line numberOriginal file lineDiff line numberDiff line change
namespace Jiminny\Component\ES\Processor\DTOs;
namespace Jiminny\Component\ES\Processor\DTOs;
use Jiminny\Component\ES\QueuePriorityEnum;
/**
/**
* A very basic and simple collection of entity IDs.
* A very basic and simple collection of entity IDs.
*/
*/
class SelectionList
class SelectionList
{
{
public function __construct(
private const int DEFAULT_CHUNK = 200;
private readonly array $priorityEntityIdList = [],
private readonly array $normalEntityIdList = [],
private int $chunkSize = self::DEFAULT_CHUNK;
private readonly bool $isStaleChunkSelected = false,
private bool $isStaleChunkSelected = false;
private readonly int $chunkSize = 200,
private array $selectedEntityIds = [];
) {
// Do nothing
public function setChunkSize(int $chunkSize): void
{
$this->chunkSize = $chunkSize;
}
}
public function getAllIds(): array
public function markStale(): void
{
{
return array_merge($this->priorityEntityIdList, $this->normalEntityIdList);
$this->isStaleChunkSelected = true;
}
}
public function count(): int
public function addEntityList(string|QueuePriorityEnum $priority, array $entityIds): void
{
{
return count($this->priorityEntityIdList) + count($this->normalEntityIdList);
$priorityKey = $this->normalisePriority($priority);
if (! array_key_exists($priorityKey, $this->selectedEntityIds)) {
$this->selectedEntityIds[$priorityKey] = [];
}
$this->selectedEntityIds[$priorityKey] = array_merge($this->selectedEntityIds[$priorityKey], $entityIds);
}
}
public function isEmpty(): bool
/**
* @return string[]
*/
public function getEntityListGroups(): array
{
{
return empty($this->priorityEntityIdList) && empty($this->normalEntityIdList);
return array_keys($this->selectedEntityIds);
}
}
public function getHighPriorityEntityIds(): array
public function getEntityListItemsByGroup(string|QueuePriorityEnum $priority): array
{
{
return $this->priorityEntityIdList;
$priorityKey = $this->normalisePriority($priority);
return $this->selectedEntityIds[$priorityKey] ?? [];
}
}
public function getNormalPriorityEntityId(): array
public function getAllIds(): array
{
{
return $this->normalEntityIdList;...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira","depth":4,"bounds":{"left":0.0,"top":0.0518755,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.06304868,"width":0.10106383,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app","depth":4,"bounds":{"left":0.0,"top":0.08459697,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app","depth":5,"bounds":{"left":0.013297873,"top":0.09577015,"width":0.18816489,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app","depth":4,"bounds":{"left":0.0,"top":0.11731844,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app","depth":5,"bounds":{"left":0.013297873,"top":0.12849163,"width":0.15674867,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.06732048,"top":0.1245012,"width":0.007978723,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New Tab","depth":4,"bounds":{"left":0.0028257978,"top":0.15163608,"width":0.07413564,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"bounds":{"left":0.0028257978,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Close Google Gemini (⌃X)","depth":6,"bounds":{"left":0.013796543,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Tabs from other devices","depth":6,"bounds":{"left":0.024933511,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"bounds":{"left":0.036070477,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"bounds":{"left":0.04720745,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"AI Chat settings","depth":7,"bounds":{"left":0.35854387,"top":0.055067837,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Close","depth":7,"bounds":{"left":0.37051198,"top":0.055067837,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"WORK, Google Account: lukas.kovalik@jiminny.com","depth":12,"bounds":{"left":0.3678524,"top":0.103751,"width":0.013297873,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Main menu","depth":12,"bounds":{"left":0.08494016,"top":0.103751,"width":0.013297873,"height":0.031923383},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New chat","depth":12,"bounds":{"left":0.09823803,"top":0.10454908,"width":0.028590426,"height":0.030327214},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Gemini","depth":15,"bounds":{"left":0.1008976,"top":0.10973663,"width":0.021941489,"height":0.020351157},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"New Chat","depth":12,"bounds":{"left":0.33992687,"top":0.103751,"width":0.013297873,"height":0.031923383},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Open menu for conversation actions.","depth":12,"bounds":{"left":0.35322472,"top":0.103751,"width":0.013297873,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXHeading","text":"Conversation with Gemini","depth":15,"bounds":{"left":0.079288565,"top":0.14764565,"width":0.0003324468,"height":0.0007980846},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Conversation with Gemini","depth":16,"bounds":{"left":0.079288565,"top":0.15003991,"width":0.1200133,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Show the uploaded image in a lightbox","depth":21,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy prompt","depth":21,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"You said Make a PR of changes Find potential issues and bottlenecks","depth":21,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"You said","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Make a PR of changes Find potential issues and bottlenecks","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Listen","depth":22,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Show thinking","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Gemini said","depth":20,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Gemini said","depth":21,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"I can see you've uploaded a screenshot of a code diff, likely from a version control system given the red and green highlights. I would love to help you review the changes, spot bottlenecks, and help you draft a Pull Request.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"However,","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"the image resolution is far too low for me to read.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"It appears to be a completely zoomed-out view where the code has been reduced to tiny, illegible pixels. Because of this, I cannot extract any text or logic to analyze.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"How You Can Share the Code","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"How You Can Share the Code","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"To help me review your code effectively, please try one of the following:","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Paste the text directly:","depth":26,"bounds":{"left":0.12599733,"top":0.0,"width":0.059175532,"height":0.016360734},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Copy the specific code blocks (both the old and new versions if possible) and paste them directly into our chat.","depth":26,"bounds":{"left":0.12599733,"top":0.0,"width":0.21476063,"height":0.038707104},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Upload the files:","depth":26,"bounds":{"left":0.12599733,"top":0.0,"width":0.042220745,"height":0.016360734},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"If the changes are extensive, you can upload the raw text or code files.","depth":26,"bounds":{"left":0.16821809,"top":0.0,"width":0.17154256,"height":0.016360734},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Take high-resolution screenshots:","depth":26,"bounds":{"left":0.12599733,"top":0.008778931,"width":0.08843085,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"If you must use images, take closer, readable screenshots of the specific functions or methods you want me to review.","depth":26,"bounds":{"left":0.12599733,"top":0.008778931,"width":0.23021941,"height":0.038707104},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Once you provide the readable code, I can dive right in to identify potential bugs, assess performance bottlenecks, and help you summarize the changes for your PR!","depth":24,"bounds":{"left":0.11336436,"top":0.06624102,"width":0.24534574,"height":0.038707104},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Good response","depth":22,"bounds":{"left":0.1100399,"top":0.12290503,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Bad response","depth":22,"bounds":{"left":0.120678194,"top":0.12290503,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Share & export","depth":21,"bounds":{"left":0.13131648,"top":0.12290503,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy","depth":22,"bounds":{"left":0.1419548,"top":0.12290503,"width":0.010638298,"height":0.025538707},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Show more options","depth":21,"bounds":{"left":0.15259309,"top":0.12290503,"width":0.010638298,"height":0.025538707},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy prompt","depth":21,"bounds":{"left":0.17121011,"top":0.18355946,"width":0.013297873,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Edit","depth":21,"bounds":{"left":0.18583776,"top":0.18355946,"width":0.013297873,"height":0.031923383},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"You said app/Component/ES/Listeners/UpdateMultipleTargetsListener.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\\Component\\ES\\Listeners; namespace Jiminny\\Component\\ES\\Listeners; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Contracts\\ES\\Events\\UpdateMultipleEntities; use Jiminny\\Contracts\\ES\\Events\\UpdateMultipleEntities; use Psr\\Log\\LoggerInterface; use Psr\\Log\\LoggerInterface; AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntities(), $event->getEntities(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } } } app/Component/ES/Listeners/UpdateSingleTargetListener.php +9-1Lines changed: 9 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Actions\\TrackElasticSearchOperations; use Jiminny\\Component\\ES\\Actions\\TrackElasticSearchOperations; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder; use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Contracts\\ES\\Events\\UpdateSingleEntity; use Jiminny\\Contracts\\ES\\Events\\UpdateSingleEntity; use Psr\\Log\\LoggerInterface; use Psr\\Log\\LoggerInterface; 'entityId' => $event->getEntityId(), 'entityId' => $event->getEntityId(), ]); ]); /** * @important: * Synchronous event should eventually be deprecated. * Instant write operations are blocking and should be used sparingly. * It is much better in terms of performance to write 100 or 1000 documents at once, * and have one blocking reindex operation, instead of writing 10 documents synchronously. */ if ($event->isSyncEvent()) { if ($event->isSyncEvent()) { $this->handleSyncEvent($event); $this->handleSyncEvent($event); AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntityId(), $event->getEntityId(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } app/Component/ES/Processor/Actions/UpsertDocumentsAction.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Processor\\DTOs\\SimpleCollection; use Jiminny\\Component\\ES\\Processor\\DTOs\\SimpleCollection; use Jiminny\\Component\\ES\\Processor\\ResponseEvaluator; use Jiminny\\Component\\ES\\Processor\\ResponseEvaluator; use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait; use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Exceptions\\InvalidDataException; use Jiminny\\Exceptions\\InvalidDataException; use Sentry\\Laravel\\Facade as Sentry; use Sentry\\Laravel\\Facade as Sentry; AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( entityType: $this->updateTarget, entityType: $this->updateTarget, entityId: (int) $document->getId(), entityId: (int) $document->getId(), withPriority: true priority: QueuePriorityEnum::HIGH, ); ); } } app/Component/ES/Processor/DTOs/SelectionList.php +54-17Lines changed: 54 additions & 17 deletions Original file line numberOriginal file lineDiff line numberDiff line change namespace Jiminny\\Component\\ES\\Processor\\DTOs; namespace Jiminny\\Component\\ES\\Processor\\DTOs; use Jiminny\\Component\\ES\\QueuePriorityEnum; /** /** * A very basic and simple collection of entity IDs. * A very basic and simple collection of entity IDs. */ */ class SelectionList class SelectionList { { public function __construct( private const int DEFAULT_CHUNK = 200; private readonly array $priorityEntityIdList = [], private readonly array $normalEntityIdList = [], private int $chunkSize = self::DEFAULT_CHUNK; private readonly bool $isStaleChunkSelected = false, private bool $isStaleChunkSelected = false; private readonly int $chunkSize = 200, private array $selectedEntityIds = []; ) { // Do nothing public function setChunkSize(int $chunkSize): void { $this->chunkSize = $chunkSize; } } public function getAllIds(): array public function markStale(): void { { return array_merge($this->priorityEntityIdList, $this->normalEntityIdList); $this->isStaleChunkSelected = true; } } public function count(): int public function addEntityList(string|QueuePriorityEnum $priority, array $entityIds): void { { return count($this->priorityEntityIdList) + count($this->normalEntityIdList); $priorityKey = $this->normalisePriority($priority); if (! array_key_exists($priorityKey, $this->selectedEntityIds)) { $this->selectedEntityIds[$priorityKey] = []; } $this->selectedEntityIds[$priorityKey] = array_merge($this->selectedEntityIds[$priorityKey], $entityIds); } } public function isEmpty(): bool /** * @return string[] */ public function getEntityListGroups(): array { { return empty($this->priorityEntityIdList) && empty($this->normalEntityIdList); return array_keys($this->selectedEntityIds); } } public function getHighPriorityEntityIds(): array public function getEntityListItemsByGroup(string|QueuePriorityEnum $priority): array { { return $this->priorityEntityIdList; $priorityKey = $this->normalisePriority($priority); return $this->selectedEntityIds[$priorityKey] ?? []; } } public function getNormalPriorityEntityId(): array public function getAllIds(): array { { return $this->normalEntityIdList; $allIds = []; foreach ($this->selectedEntityIds as $entityIds) { $allIds = array_merge($allIds, $entityIds); } return $allIds; } public function count(): int { return array_sum( array_map('count', $this->selectedEntityIds) ); } public function isEmpty(): bool { return $this->count() === 0; } } public function isStaleChunkSelected(): bool public function isStaleChunkSelected(): bool { { return $this->count() >= $this->chunkSize; return $this->count() >= $this->chunkSize; } } private function normalisePriority(string|QueuePriorityEnum $priority): string { return $priority instanceof QueuePriorityEnum ? $priority->value : $priority; } } } app/Component/ES/Processor/Traits/SelectEntityListTrait.php +27-4Lines changed: 27 additions & 4 deletions Original file line numberOriginal file lineDiff line numberDiff line change use Illuminate\\Support\\Facades\\Log; use Illuminate\\Support\\Facades\\Log; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Exceptions\\InvalidArgumentException; use Jiminny\\Exceptions\\InvalidArgumentException; /** /** * Build the correct source list name for the type of entity and priority * Build the correct source list name for the type of entity and priority */ */ trait SelectEntityListTrait trait SelectEntityListTrait { { /** * Highest priority queue for data requiring near-instant availability. * Very few entities should be added here, only when absolutely necessary. */ private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; /** * Normal priority queue for normal application operations. * Almost all update events should pass through this queue */ private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; protected static function selectTargetList(string $entityType, bool $withPriority = false): string /** { * Nonblocking low priority queue. This queue will be consumed only when there is nothing * with higher priority. * * This queue will be used for operations such as es:reset-async */ private const string ENTITIES_LOW_PRIORITIES_LIST = '%s-for-update-low'; protected static function selectTargetList( string $entityType, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { if (! in_array($entityType, UpdateTarget::allowedTargets())) { if (! in_array($entityType, UpdateTarget::allowedTargets())) { throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); } } if ($withPriority) { if ($priority->isHigh()) { Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); } } if ($priority->isLow()) { return sprintf(self::ENTITIES_LOW_PRIORITIES_LIST, $entityType); } return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); } } } } app/Component/ES/Processor/TargetEntitiesSelector.php +26-21Lines changed: 26 additions & 21 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Processor\\DTOs\\SelectionList; use Jiminny\\Component\\ES\\Processor\\DTOs\\SelectionList; use Jiminny\\Component\\ES\\Processor\\Traits\\ExtractIdsTrait; use Jiminny\\Component\\ES\\Processor\\Traits\\ExtractIdsTrait; use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait; use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait; use Jiminny\\Component\\ES\\QueuePriorityEnum; /** /** * This class supplies a list of entities pending an update. * This class supplies a list of entities pending an update. public function select(): SelectionList public function select(): SelectionList { { $staleWorkEntityIds = $this->getStaleChunk(); $selectionList = new SelectionList(); $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $staleWorkEntityIds = $this->getStaleChunk(); if (count($staleWorkEntityIds) > 0) { if (count($staleWorkEntityIds) > 0) { return new SelectionList( /** priorityEntityIdList: $staleWorkEntityIds, * Stale chunks are treated as high priority isStaleChunkSelected: true, */ chunkSize: ChunkSize::getStaleChunkSize($this->updateTarget), $selectionList->markStale(); ); $selectionList->addEntityList(QueuePriorityEnum::HIGH, $staleWorkEntityIds); $selectionList->setChunkSize(ChunkSize::getStaleChunkSize($this->updateTarget)); return $selectionList; } } $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $selectionList->setChunkSize($mainChunkSize); $priorityEntityIdsList = $this->extractIdsFromSet( $priorityEntityIdsList = $this->extractIds(QueuePriorityEnum::HIGH, $mainChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, true), $selectionList->addEntityList(QueuePriorityEnum::HIGH, $priorityEntityIdsList); $mainChunkSize, ); $normalEntityIdsList = []; $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); if ($normalEntityChunkSize > 0) { if ($normalEntityChunkSize > 0) { $normalEntityIdsList = $this->extractIdsFromSet( $normalEntityIdsList = $this->extractIds(QueuePriorityEnum::NORMAL, $normalEntityChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, false), $selectionList->addEntityList(QueuePriorityEnum::NORMAL, $normalEntityIdsList); $normalEntityChunkSize ); } } return new SelectionList( return $selectionList; priorityEntityIdList: $priorityEntityIdsList, normalEntityIdList: $normalEntityIdsList, chunkSize: $mainChunkSize ); } } private function getStaleChunk(): array private function getStaleChunk(): array return []; return []; } } private function extractIds(QueuePriorityEnum $priority, int $chunkSize): array { return $this->extractIdsFromSet( AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, $priority), $chunkSize ); } } } app/Component/ES/AsyncUpdateElasticSearch.php +17-10Lines changed: 17 additions & 10 deletions Original file line numberOriginal file lineDiff line numberDiff line change * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * and other activity related data * and other activity related data */ */ public static function markEntityForUpdate(string $entityType, int $entityId, bool $withPriority = false): void public static function markEntityForUpdate( { string $entityType, $targetList = self::selectTargetList($entityType, $withPriority); int $entityId, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { $targetList = self::selectTargetList($entityType, $priority); Redis::sadd($targetList, $entityId); Redis::sadd($targetList, $entityId); Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ 'entityType' => $entityType, 'entityType' => $entityType, 'entityId' => $entityId, 'entityId' => $entityId, 'collectionKey' => $targetList, 'collectionKey' => $targetList, 'withPriority' => $withPriority, 'priority' => $priority->value, ]); ]); } } public static function bulkMarkEntitiesForUpdate( public static function bulkMarkEntitiesForUpdate( string $entityType, string $entityType, array $entityIds, array $entityIds, bool $withPriority = false QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { ): void { if (empty($entityIds)) { if (empty($entityIds)) { return; return; } } $targetList = self::selectTargetList($entityType, $withPriority); $targetList = self::selectTargetList($entityType, $priority); Redis::saddarray($targetList, $entityIds); Redis::saddarray($targetList, $entityIds); } } * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Takes priority into consideration. * Takes priority into consideration. */ */ public static function getEntitiesSourceList(string $updateTarget, $priority = false): string public static function getEntitiesSourceList( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { return self::selectTargetList($updateTarget, $priority); return self::selectTargetList($updateTarget, $priority); } } /** /** * Externally called helper methods * Externally called helper methods * - count and flush * - count and flush */ */ public static function getEntitiesListCount(string $updateTarget, $priority = false): int public static function getEntitiesListCount( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): int { $targetList = self::selectTargetList($updateTarget, $priority); $targetList = self::selectTargetList($updateTarget, $priority); return Redis::scard($targetList); return Redis::scard($targetList); app/Component/ES/QueuePriorityEnum.php +40Lines changed: 40 additions & 0 deletions Original file line numberOriginal file lineDiff line numberDiff line change <?php declare(strict_types=1); namespace Jiminny\\Component\\ES; use Jiminny\\Exceptions\\InvalidArgumentException; enum QueuePriorityEnum: string { case HIGH = 'high'; case NORMAL = 'normal'; case LOW = 'low'; public static function tryFromString(string $value): self { if (! self::isValid($value)) { throw new InvalidArgumentException( sprintf('Invalid queue priority \"%s\" selected', $value) ); } return self::tryFrom($value); } public static function isValid(string $value): bool { return self::tryFrom($value) !== null; } public function isLow(): bool { return $this === self::LOW; } public function isHigh(): bool { return $this === self::HIGH; } } app/Component/ES/UpdateProcessManager.php +12-9Lines changed: 12 additions & 9 deletions Original file line numberOriginal file lineDiff line numberDiff line change if ($selectionList->isEmpty()) { if ($selectionList->isEmpty()) { return false; return false; } } /** /** * A stale chunk will always be smaller than a regular chunk. * A stale chunk will always be smaller than a regular chunk. * That doesn't mean there aren't any other scheduled entities for processing * That doesn't mean there aren't any other scheduled entities for processing private function rescheduleThrottledEntities(SelectionList $selectionList): void private function rescheduleThrottledEntities(SelectionList $selectionList): void { { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $groups = $selectionList->getEntityListGroups(); $this->updateTarget, foreach ($groups as $eachGroup) { $selectionList->getNormalPriorityEntityId() $groupEntityIds = $selectionList->getEntityListItemsByGroup($eachGroup); ); if (! empty($groupEntityIds)) { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $this->updateTarget, entityType: $this->updateTarget, $selectionList->getHighPriorityEntityIds(), entityIds: $groupEntityIds, true priority: QueuePriorityEnum::tryFromString($eachGroup) ); ); } } } } } } app/Console/Commands/Elasticsearch/AsyncUpdateEsEntities.php +9-3Lines changed: 9 additions & 3 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Illuminate\\Support\\Str; use Illuminate\\Support\\Str; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Component\\ES\\UpdateProcessManager; use Jiminny\\Component\\ES\\UpdateProcessManager; use Jiminny\\Exceptions\\InvalidArgumentException; use Jiminny\\Exceptions\\InvalidArgumentException; use Jiminny\\Traits\\GracefullyStoppable; use Jiminny\\Traits\\GracefullyStoppable; Redis::set($gaugeLockName, true); Redis::set($gaugeLockName, true); Redis::expire($gaugeLockName, 60); Redis::expire($gaugeLockName, 60); $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::HIGH), ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update', $updateTarget), stat: sprintf('jiminny.%s-for-update', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::NORMAL), ); ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), stat: sprintf('jiminny.%s-for-update-low', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, true), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::LOW), ); ); } } app/Console/Commands/Elasticsearch/ResetAsyncElasticSearchCommand.php +5-1Lines changed: 5 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder; use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder; use Jiminny\\Component\\ES\\Processor\\Traits\\ValidateUpdateTargetTrait; use Jiminny\\Component\\ES\\Processor\\Traits\\ValidateUpdateTargetTrait; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Component\\ES\\Repositories\\EsResetRepositoryInterface; use Jiminny\\Component\\ES\\Repositories\\EsResetRepositoryInterface; use Jiminny\\Exceptions\\InvalidArgumentException; use Jiminny\\Exceptions\\InvalidArgumentException; use Jiminny\\Traits\\GracefullyStoppable; use Jiminny\\Traits\\GracefullyStoppable; private function getRemainingScheduledEntities(bool $printStatus = false): int private function getRemainingScheduledEntities(bool $printStatus = false): int { { $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget, true); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount( $this->updateTarget, QueuePriorityEnum::HIGH ); if ($printStatus) { if ($printStatus) { $this->line( $this->line(","depth":21,"bounds":{"left":0.20578457,"top":0.19313647,"width":0.13696809,"height":0.09577015},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"You said","depth":23,"bounds":{"left":0.079288565,"top":0.19393456,"width":0.019946808,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app/Component/ES/Listeners/UpdateMultipleTargetsListener.php","depth":23,"bounds":{"left":0.20578457,"top":0.19473264,"width":0.084773935,"height":0.035514764},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"+2-1Lines changed: 2 additions & 1 deletion","depth":23,"bounds":{"left":0.20578457,"top":0.25219473,"width":0.10388963,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\\Component\\ES\\Listeners;","depth":23,"bounds":{"left":0.20578457,"top":0.2905028,"width":0.11303192,"height":0.054668795},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"namespace Jiminny\\Component\\ES\\Listeners;","depth":23,"bounds":{"left":0.20578457,"top":0.34796488,"width":0.1100399,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch;","depth":23,"bounds":{"left":0.20578457,"top":0.40542698,"width":0.13380983,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch;","depth":23,"bounds":{"left":0.20578457,"top":0.424581,"width":0.13380983,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\QueuePriorityEnum;","depth":23,"bounds":{"left":0.20578457,"top":0.4820431,"width":0.115359046,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Contracts\\ES\\Events\\UpdateMultipleEntities;","depth":23,"bounds":{"left":0.20578457,"top":0.5011971,"width":0.13597074,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Contracts\\ES\\Events\\UpdateMultipleEntities;","depth":23,"bounds":{"left":0.20578457,"top":0.5203512,"width":0.13597074,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Psr\\Log\\LoggerInterface;","depth":23,"bounds":{"left":0.20578457,"top":0.5395052,"width":0.07047872,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Psr\\Log\\LoggerInterface;","depth":23,"bounds":{"left":0.20578457,"top":0.5586592,"width":0.07047872,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(","depth":23,"bounds":{"left":0.20578457,"top":0.6161213,"width":0.13530585,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(","depth":23,"bounds":{"left":0.20578457,"top":0.63527536,"width":0.13530585,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getUpdateTargetValue(),","depth":23,"bounds":{"left":0.20578457,"top":0.6544294,"width":0.0809508,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getUpdateTargetValue(),","depth":23,"bounds":{"left":0.20578457,"top":0.6735834,"width":0.0809508,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getEntities(),","depth":23,"bounds":{"left":0.20578457,"top":0.6927374,"width":0.052526597,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getEntities(),","depth":23,"bounds":{"left":0.20578457,"top":0.7118915,"width":0.052526597,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->isPriority()","depth":23,"bounds":{"left":0.20578457,"top":0.7310455,"width":0.046708778,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL,","depth":23,"bounds":{"left":0.20578457,"top":0.7501995,"width":0.11702128,"height":0.035514764},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":");","depth":23,"bounds":{"left":0.20578457,"top":0.7885076,"width":0.0033244682,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":");","depth":23,"bounds":{"left":0.20578457,"top":0.8076616,"width":0.0033244682,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"bounds":{"left":0.20578457,"top":0.82681566,"width":0.0019946808,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"bounds":{"left":0.20578457,"top":0.8459697,"width":0.0019946808,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"bounds":{"left":0.20578457,"top":0.8651237,"width":0.0019946808,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"bounds":{"left":0.20578457,"top":0.88427776,"width":0.0019946808,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app/Component/ES/Listeners/UpdateSingleTargetListener.php","depth":23,"bounds":{"left":0.20578457,"top":0.9034318,"width":0.07762633,"height":0.035514764},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"+9-1Lines changed: 9 additions & 1 deletion","depth":23,"bounds":{"left":0.20578457,"top":0.96089387,"width":0.104222074,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Actions\\TrackElasticSearchOperations;","depth":23,"bounds":{"left":0.20578457,"top":0.9992019,"width":0.13480718,"height":0.0007981062},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Actions\\TrackElasticSearchOperations;","depth":23,"bounds":{"left":0.20578457,"top":1.0,"width":0.13480718,"height":-0.07581806},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\QueuePriorityEnum;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Contracts\\ES\\Events\\UpdateSingleEntity;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Contracts\\ES\\Events\\UpdateSingleEntity;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Psr\\Log\\LoggerInterface;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Psr\\Log\\LoggerInterface;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"'entityId' => $event->getEntityId(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"'entityId' => $event->getEntityId(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"]);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"]);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/**","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* @important:","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* Synchronous event should eventually be deprecated.","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* Instant write operations are blocking and should be used sparingly.","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* It is much better in terms of performance to write 100 or 1000 documents at once,","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* and have one blocking reindex operation, instead of writing 10 documents synchronously.","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"*/","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"if ($event->isSyncEvent()) {","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"if ($event->isSyncEvent()) {","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$this->handleSyncEvent($event);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$this->handleSyncEvent($event);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AsyncUpdateElasticSearch::markEntityForUpdate(","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AsyncUpdateElasticSearch::markEntityForUpdate(","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getUpdateTargetValue(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getUpdateTargetValue(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getEntityId(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getEntityId(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->isPriority()","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL,","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":");","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":");","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app/Component/ES/Processor/Actions/UpsertDocumentsAction.php","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"+2-1Lines changed: 2 additions & 1 deletion","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Processor\\DTOs\\SimpleCollection;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\DTOs\\SimpleCollection;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\ResponseEvaluator;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\ResponseEvaluator;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\QueuePriorityEnum;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Exceptions\\InvalidDataException;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Exceptions\\InvalidDataException;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Sentry\\Laravel\\Facade as Sentry;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Sentry\\Laravel\\Facade as Sentry;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AsyncUpdateElasticSearch::markEntityForUpdate(","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AsyncUpdateElasticSearch::markEntityForUpdate(","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"entityType: $this->updateTarget,","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"entityType: $this->updateTarget,","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"entityId: (int) $document->getId(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"entityId: (int) $document->getId(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"withPriority: true","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"priority: QueuePriorityEnum::HIGH,","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":");","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":");","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app/Component/ES/Processor/DTOs/SelectionList.php","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"+54-17Lines changed: 54 additions & 17 deletions","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Original file line numberOriginal file lineDiff line numberDiff line change","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"namespace Jiminny\\Component\\ES\\Processor\\DTOs;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"namespace Jiminny\\Component\\ES\\Processor\\DTOs;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\QueuePriorityEnum;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/**","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/**","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* A very basic and simple collection of entity IDs.","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* A very basic and simple collection of entity IDs.","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"*/","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"*/","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"class SelectionList","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"class SelectionList","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function __construct(","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private const int DEFAULT_CHUNK = 200;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private readonly array $priorityEntityIdList = [],","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private readonly array $normalEntityIdList = [],","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private int $chunkSize = self::DEFAULT_CHUNK;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private readonly bool $isStaleChunkSelected = false,","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private bool $isStaleChunkSelected = false;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private readonly int $chunkSize = 200,","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private array $selectedEntityIds = [];","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":") {","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"// Do nothing","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function setChunkSize(int $chunkSize): void","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$this->chunkSize = $chunkSize;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function getAllIds(): array","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function markStale(): void","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"return array_merge($this->priorityEntityIdList, $this->normalEntityIdList);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$this->isStaleChunkSelected = true;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function count(): int","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function addEntityList(string|QueuePriorityEnum $priority, array $entityIds): void","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"return count($this->priorityEntityIdList) + count($this->normalEntityIdList);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$priorityKey = $this->normalisePriority($priority);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"if (! array_key_exists($priorityKey, $this->selectedEntityIds)) {","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$this->selectedEntityIds[$priorityKey] = [];","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$this->selectedEntityIds[$priorityKey] = array_merge($this->selectedEntityIds[$priorityKey], $entityIds);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function isEmpty(): bool","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/**","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* @return string[]","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"*/","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function getEntityListGroups(): array","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"return empty($this->priorityEntityIdList) && empty($this->normalEntityIdList);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"return array_keys($this->selectedEntityIds);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function getHighPriorityEntityIds(): array","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function getEntityListItemsByGroup(string|QueuePriorityEnum $priority): array","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"return $this->priorityEntityIdList;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$priorityKey = $this->normalisePriority($priority);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"return $this->selectedEntityIds[$priorityKey] ?? [];","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function getNormalPriorityEntityId(): array","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function getAllIds(): array","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"return $this->normalEntityIdList;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"}]...
|
-5882629797860530957
|
-1144453838252598130
|
click
|
accessibility
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
Close tab
New Tab
Customize sidebar
Close Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
AI Chat settings
Close
WORK, Google Account: [EMAIL]
Main menu
New chat
Gemini
New Chat
Open menu for conversation actions.
Conversation with Gemini
Conversation with Gemini
Show the uploaded image in a lightbox
Copy prompt
You said Make a PR of changes Find potential issues and bottlenecks
You said
Make a PR of changes Find potential issues and bottlenecks
Listen
Show thinking
Gemini said
Gemini said
I can see you've uploaded a screenshot of a code diff, likely from a version control system given the red and green highlights. I would love to help you review the changes, spot bottlenecks, and help you draft a Pull Request.
However,
the image resolution is far too low for me to read.
It appears to be a completely zoomed-out view where the code has been reduced to tiny, illegible pixels. Because of this, I cannot extract any text or logic to analyze.
How You Can Share the Code
How You Can Share the Code
To help me review your code effectively, please try one of the following:
Paste the text directly:
Copy the specific code blocks (both the old and new versions if possible) and paste them directly into our chat.
Upload the files:
If the changes are extensive, you can upload the raw text or code files.
Take high-resolution screenshots:
If you must use images, take closer, readable screenshots of the specific functions or methods you want me to review.
Once you provide the readable code, I can dive right in to identify potential bugs, assess performance bottlenecks, and help you summarize the changes for your PR!
Good response
Bad response
Share & export
Copy
Show more options
Copy prompt
Edit
You said app/Component/ES/Listeners/UpdateMultipleTargetsListener.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\Component\ES\Listeners; namespace Jiminny\Component\ES\Listeners; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Contracts\ES\Events\UpdateMultipleEntities; use Jiminny\Contracts\ES\Events\UpdateMultipleEntities; use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface; AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntities(), $event->getEntities(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } } } app/Component/ES/Listeners/UpdateSingleTargetListener.php +9-1Lines changed: 9 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Actions\TrackElasticSearchOperations; use Jiminny\Component\ES\Actions\TrackElasticSearchOperations; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Contracts\ES\Events\UpdateSingleEntity; use Jiminny\Contracts\ES\Events\UpdateSingleEntity; use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface; 'entityId' => $event->getEntityId(), 'entityId' => $event->getEntityId(), ]); ]); /** * @important: * Synchronous event should eventually be deprecated. * Instant write operations are blocking and should be used sparingly. * It is much better in terms of performance to write 100 or 1000 documents at once, * and have one blocking reindex operation, instead of writing 10 documents synchronously. */ if ($event->isSyncEvent()) { if ($event->isSyncEvent()) { $this->handleSyncEvent($event); $this->handleSyncEvent($event); AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntityId(), $event->getEntityId(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } app/Component/ES/Processor/Actions/UpsertDocumentsAction.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SimpleCollection; use Jiminny\Component\ES\Processor\DTOs\SimpleCollection; use Jiminny\Component\ES\Processor\ResponseEvaluator; use Jiminny\Component\ES\Processor\ResponseEvaluator; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Exceptions\InvalidDataException; use Jiminny\Exceptions\InvalidDataException; use Sentry\Laravel\Facade as Sentry; use Sentry\Laravel\Facade as Sentry; AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( entityType: $this->updateTarget, entityType: $this->updateTarget, entityId: (int) $document->getId(), entityId: (int) $document->getId(), withPriority: true priority: QueuePriorityEnum::HIGH, ); ); } } app/Component/ES/Processor/DTOs/SelectionList.php +54-17Lines changed: 54 additions & 17 deletions Original file line numberOriginal file lineDiff line numberDiff line change namespace Jiminny\Component\ES\Processor\DTOs; namespace Jiminny\Component\ES\Processor\DTOs; use Jiminny\Component\ES\QueuePriorityEnum; /** /** * A very basic and simple collection of entity IDs. * A very basic and simple collection of entity IDs. */ */ class SelectionList class SelectionList { { public function __construct( private const int DEFAULT_CHUNK = 200; private readonly array $priorityEntityIdList = [], private readonly array $normalEntityIdList = [], private int $chunkSize = self::DEFAULT_CHUNK; private readonly bool $isStaleChunkSelected = false, private bool $isStaleChunkSelected = false; private readonly int $chunkSize = 200, private array $selectedEntityIds = []; ) { // Do nothing public function setChunkSize(int $chunkSize): void { $this->chunkSize = $chunkSize; } } public function getAllIds(): array public function markStale(): void { { return array_merge($this->priorityEntityIdList, $this->normalEntityIdList); $this->isStaleChunkSelected = true; } } public function count(): int public function addEntityList(string|QueuePriorityEnum $priority, array $entityIds): void { { return count($this->priorityEntityIdList) + count($this->normalEntityIdList); $priorityKey = $this->normalisePriority($priority); if (! array_key_exists($priorityKey, $this->selectedEntityIds)) { $this->selectedEntityIds[$priorityKey] = []; } $this->selectedEntityIds[$priorityKey] = array_merge($this->selectedEntityIds[$priorityKey], $entityIds); } } public function isEmpty(): bool /** * @return string[] */ public function getEntityListGroups(): array { { return empty($this->priorityEntityIdList) && empty($this->normalEntityIdList); return array_keys($this->selectedEntityIds); } } public function getHighPriorityEntityIds(): array public function getEntityListItemsByGroup(string|QueuePriorityEnum $priority): array { { return $this->priorityEntityIdList; $priorityKey = $this->normalisePriority($priority); return $this->selectedEntityIds[$priorityKey] ?? []; } } public function getNormalPriorityEntityId(): array public function getAllIds(): array { { return $this->normalEntityIdList; $allIds = []; foreach ($this->selectedEntityIds as $entityIds) { $allIds = array_merge($allIds, $entityIds); } return $allIds; } public function count(): int { return array_sum( array_map('count', $this->selectedEntityIds) ); } public function isEmpty(): bool { return $this->count() === 0; } } public function isStaleChunkSelected(): bool public function isStaleChunkSelected(): bool { { return $this->count() >= $this->chunkSize; return $this->count() >= $this->chunkSize; } } private function normalisePriority(string|QueuePriorityEnum $priority): string { return $priority instanceof QueuePriorityEnum ? $priority->value : $priority; } } } app/Component/ES/Processor/Traits/SelectEntityListTrait.php +27-4Lines changed: 27 additions & 4 deletions Original file line numberOriginal file lineDiff line numberDiff line change use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; /** /** * Build the correct source list name for the type of entity and priority * Build the correct source list name for the type of entity and priority */ */ trait SelectEntityListTrait trait SelectEntityListTrait { { /** * Highest priority queue for data requiring near-instant availability. * Very few entities should be added here, only when absolutely necessary. */ private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; /** * Normal priority queue for normal application operations. * Almost all update events should pass through this queue */ private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; protected static function selectTargetList(string $entityType, bool $withPriority = false): string /** { * Nonblocking low priority queue. This queue will be consumed only when there is nothing * with higher priority. * * This queue will be used for operations such as es:reset-async */ private const string ENTITIES_LOW_PRIORITIES_LIST = '%s-for-update-low'; protected static function selectTargetList( string $entityType, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { if (! in_array($entityType, UpdateTarget::allowedTargets())) { if (! in_array($entityType, UpdateTarget::allowedTargets())) { throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); } } if ($withPriority) { if ($priority->isHigh()) { Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); } } if ($priority->isLow()) { return sprintf(self::ENTITIES_LOW_PRIORITIES_LIST, $entityType); } return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); } } } } app/Component/ES/Processor/TargetEntitiesSelector.php +26-21Lines changed: 26 additions & 21 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SelectionList; use Jiminny\Component\ES\Processor\DTOs\SelectionList; use Jiminny\Component\ES\Processor\Traits\ExtractIdsTrait; use Jiminny\Component\ES\Processor\Traits\ExtractIdsTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\QueuePriorityEnum; /** /** * This class supplies a list of entities pending an update. * This class supplies a list of entities pending an update. public function select(): SelectionList public function select(): SelectionList { { $staleWorkEntityIds = $this->getStaleChunk(); $selectionList = new SelectionList(); $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $staleWorkEntityIds = $this->getStaleChunk(); if (count($staleWorkEntityIds) > 0) { if (count($staleWorkEntityIds) > 0) { return new SelectionList( /** priorityEntityIdList: $staleWorkEntityIds, * Stale chunks are treated as high priority isStaleChunkSelected: true, */ chunkSize: ChunkSize::getStaleChunkSize($this->updateTarget), $selectionList->markStale(); ); $selectionList->addEntityList(QueuePriorityEnum::HIGH, $staleWorkEntityIds); $selectionList->setChunkSize(ChunkSize::getStaleChunkSize($this->updateTarget)); return $selectionList; } } $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $selectionList->setChunkSize($mainChunkSize); $priorityEntityIdsList = $this->extractIdsFromSet( $priorityEntityIdsList = $this->extractIds(QueuePriorityEnum::HIGH, $mainChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, true), $selectionList->addEntityList(QueuePriorityEnum::HIGH, $priorityEntityIdsList); $mainChunkSize, ); $normalEntityIdsList = []; $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); if ($normalEntityChunkSize > 0) { if ($normalEntityChunkSize > 0) { $normalEntityIdsList = $this->extractIdsFromSet( $normalEntityIdsList = $this->extractIds(QueuePriorityEnum::NORMAL, $normalEntityChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, false), $selectionList->addEntityList(QueuePriorityEnum::NORMAL, $normalEntityIdsList); $normalEntityChunkSize ); } } return new SelectionList( return $selectionList; priorityEntityIdList: $priorityEntityIdsList, normalEntityIdList: $normalEntityIdsList, chunkSize: $mainChunkSize ); } } private function getStaleChunk(): array private function getStaleChunk(): array return []; return []; } } private function extractIds(QueuePriorityEnum $priority, int $chunkSize): array { return $this->extractIdsFromSet( AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, $priority), $chunkSize ); } } } app/Component/ES/AsyncUpdateElasticSearch.php +17-10Lines changed: 17 additions & 10 deletions Original file line numberOriginal file lineDiff line numberDiff line change * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * and other activity related data * and other activity related data */ */ public static function markEntityForUpdate(string $entityType, int $entityId, bool $withPriority = false): void public static function markEntityForUpdate( { string $entityType, $targetList = self::selectTargetList($entityType, $withPriority); int $entityId, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { $targetList = self::selectTargetList($entityType, $priority); Redis::sadd($targetList, $entityId); Redis::sadd($targetList, $entityId); Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ 'entityType' => $entityType, 'entityType' => $entityType, 'entityId' => $entityId, 'entityId' => $entityId, 'collectionKey' => $targetList, 'collectionKey' => $targetList, 'withPriority' => $withPriority, 'priority' => $priority->value, ]); ]); } } public static function bulkMarkEntitiesForUpdate( public static function bulkMarkEntitiesForUpdate( string $entityType, string $entityType, array $entityIds, array $entityIds, bool $withPriority = false QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { ): void { if (empty($entityIds)) { if (empty($entityIds)) { return; return; } } $targetList = self::selectTargetList($entityType, $withPriority); $targetList = self::selectTargetList($entityType, $priority); Redis::saddarray($targetList, $entityIds); Redis::saddarray($targetList, $entityIds); } } * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Takes priority into consideration. * Takes priority into consideration. */ */ public static function getEntitiesSourceList(string $updateTarget, $priority = false): string public static function getEntitiesSourceList( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { return self::selectTargetList($updateTarget, $priority); return self::selectTargetList($updateTarget, $priority); } } /** /** * Externally called helper methods * Externally called helper methods * - count and flush * - count and flush */ */ public static function getEntitiesListCount(string $updateTarget, $priority = false): int public static function getEntitiesListCount( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): int { $targetList = self::selectTargetList($updateTarget, $priority); $targetList = self::selectTargetList($updateTarget, $priority); return Redis::scard($targetList); return Redis::scard($targetList); app/Component/ES/QueuePriorityEnum.php +40Lines changed: 40 additions & 0 deletions Original file line numberOriginal file lineDiff line numberDiff line change <?php declare(strict_types=1); namespace Jiminny\Component\ES; use Jiminny\Exceptions\InvalidArgumentException; enum QueuePriorityEnum: string { case HIGH = 'high'; case NORMAL = 'normal'; case LOW = 'low'; public static function tryFromString(string $value): self { if (! self::isValid($value)) { throw new InvalidArgumentException( sprintf('Invalid queue priority "%s" selected', $value) ); } return self::tryFrom($value); } public static function isValid(string $value): bool { return self::tryFrom($value) !== null; } public function isLow(): bool { return $this === self::LOW; } public function isHigh(): bool { return $this === self::HIGH; } } app/Component/ES/UpdateProcessManager.php +12-9Lines changed: 12 additions & 9 deletions Original file line numberOriginal file lineDiff line numberDiff line change if ($selectionList->isEmpty()) { if ($selectionList->isEmpty()) { return false; return false; } } /** /** * A stale chunk will always be smaller than a regular chunk. * A stale chunk will always be smaller than a regular chunk. * That doesn't mean there aren't any other scheduled entities for processing * That doesn't mean there aren't any other scheduled entities for processing private function rescheduleThrottledEntities(SelectionList $selectionList): void private function rescheduleThrottledEntities(SelectionList $selectionList): void { { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $groups = $selectionList->getEntityListGroups(); $this->updateTarget, foreach ($groups as $eachGroup) { $selectionList->getNormalPriorityEntityId() $groupEntityIds = $selectionList->getEntityListItemsByGroup($eachGroup); ); if (! empty($groupEntityIds)) { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $this->updateTarget, entityType: $this->updateTarget, $selectionList->getHighPriorityEntityIds(), entityIds: $groupEntityIds, true priority: QueuePriorityEnum::tryFromString($eachGroup) ); ); } } } } } } app/Console/Commands/Elasticsearch/AsyncUpdateEsEntities.php +9-3Lines changed: 9 additions & 3 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Illuminate\Support\Str; use Illuminate\Support\Str; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Component\ES\UpdateProcessManager; use Jiminny\Component\ES\UpdateProcessManager; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Traits\GracefullyStoppable; use Jiminny\Traits\GracefullyStoppable; Redis::set($gaugeLockName, true); Redis::set($gaugeLockName, true); Redis::expire($gaugeLockName, 60); Redis::expire($gaugeLockName, 60); $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::HIGH), ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update', $updateTarget), stat: sprintf('jiminny.%s-for-update', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::NORMAL), ); ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), stat: sprintf('jiminny.%s-for-update-low', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, true), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::LOW), ); ); } } app/Console/Commands/Elasticsearch/ResetAsyncElasticSearchCommand.php +5-1Lines changed: 5 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\Traits\ValidateUpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\ValidateUpdateTargetTrait; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Component\ES\Repositories\EsResetRepositoryInterface; use Jiminny\Component\ES\Repositories\EsResetRepositoryInterface; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Traits\GracefullyStoppable; use Jiminny\Traits\GracefullyStoppable; private function getRemainingScheduledEntities(bool $printStatus = false): int private function getRemainingScheduledEntities(bool $printStatus = false): int { { $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget, true); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount( $this->updateTarget, QueuePriorityEnum::HIGH ); if ($printStatus) { if ($printStatus) { $this->line( $this->line(
You said
app/Component/ES/Listeners/UpdateMultipleTargetsListener.php
+2-1Lines changed: 2 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\Component\ES\Listeners;
namespace Jiminny\Component\ES\Listeners;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\QueuePriorityEnum;
use Jiminny\Contracts\ES\Events\UpdateMultipleEntities;
use Jiminny\Contracts\ES\Events\UpdateMultipleEntities;
use Psr\Log\LoggerInterface;
use Psr\Log\LoggerInterface;
AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(
AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(
$event->getUpdateTargetValue(),
$event->getUpdateTargetValue(),
$event->getEntities(),
$event->getEntities(),
$event->isPriority()
$event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL,
);
);
}
}
}
}
app/Component/ES/Listeners/UpdateSingleTargetListener.php
+9-1Lines changed: 9 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Actions\TrackElasticSearchOperations;
use Jiminny\Component\ES\Actions\TrackElasticSearchOperations;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\Processor\EntityQueryBuilder;
use Jiminny\Component\ES\Processor\EntityQueryBuilder;
use Jiminny\Component\ES\QueuePriorityEnum;
use Jiminny\Contracts\ES\Events\UpdateSingleEntity;
use Jiminny\Contracts\ES\Events\UpdateSingleEntity;
use Psr\Log\LoggerInterface;
use Psr\Log\LoggerInterface;
'entityId' => $event->getEntityId(),
'entityId' => $event->getEntityId(),
]);
]);
/**
* @important:
* Synchronous event should eventually be deprecated.
* Instant write operations are blocking and should be used sparingly.
* It is much better in terms of performance to write 100 or 1000 documents at once,
* and have one blocking reindex operation, instead of writing 10 documents synchronously.
*/
if ($event->isSyncEvent()) {
if ($event->isSyncEvent()) {
$this->handleSyncEvent($event);
$this->handleSyncEvent($event);
AsyncUpdateElasticSearch::markEntityForUpdate(
AsyncUpdateElasticSearch::markEntityForUpdate(
$event->getUpdateTargetValue(),
$event->getUpdateTargetValue(),
$event->getEntityId(),
$event->getEntityId(),
$event->isPriority()
$event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL,
);
);
}
}
app/Component/ES/Processor/Actions/UpsertDocumentsAction.php
+2-1Lines changed: 2 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SimpleCollection;
use Jiminny\Component\ES\Processor\DTOs\SimpleCollection;
use Jiminny\Component\ES\Processor\ResponseEvaluator;
use Jiminny\Component\ES\Processor\ResponseEvaluator;
use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait;
use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait;
use Jiminny\Component\ES\QueuePriorityEnum;
use Jiminny\Exceptions\InvalidDataException;
use Jiminny\Exceptions\InvalidDataException;
use Sentry\Laravel\Facade as Sentry;
use Sentry\Laravel\Facade as Sentry;
AsyncUpdateElasticSearch::markEntityForUpdate(
AsyncUpdateElasticSearch::markEntityForUpdate(
entityType: $this->updateTarget,
entityType: $this->updateTarget,
entityId: (int) $document->getId(),
entityId: (int) $document->getId(),
withPriority: true
priority: QueuePriorityEnum::HIGH,
);
);
}
}
app/Component/ES/Processor/DTOs/SelectionList.php
+54-17Lines changed: 54 additions & 17 deletions
Original file line numberOriginal file lineDiff line numberDiff line change
namespace Jiminny\Component\ES\Processor\DTOs;
namespace Jiminny\Component\ES\Processor\DTOs;
use Jiminny\Component\ES\QueuePriorityEnum;
/**
/**
* A very basic and simple collection of entity IDs.
* A very basic and simple collection of entity IDs.
*/
*/
class SelectionList
class SelectionList
{
{
public function __construct(
private const int DEFAULT_CHUNK = 200;
private readonly array $priorityEntityIdList = [],
private readonly array $normalEntityIdList = [],
private int $chunkSize = self::DEFAULT_CHUNK;
private readonly bool $isStaleChunkSelected = false,
private bool $isStaleChunkSelected = false;
private readonly int $chunkSize = 200,
private array $selectedEntityIds = [];
) {
// Do nothing
public function setChunkSize(int $chunkSize): void
{
$this->chunkSize = $chunkSize;
}
}
public function getAllIds(): array
public function markStale(): void
{
{
return array_merge($this->priorityEntityIdList, $this->normalEntityIdList);
$this->isStaleChunkSelected = true;
}
}
public function count(): int
public function addEntityList(string|QueuePriorityEnum $priority, array $entityIds): void
{
{
return count($this->priorityEntityIdList) + count($this->normalEntityIdList);
$priorityKey = $this->normalisePriority($priority);
if (! array_key_exists($priorityKey, $this->selectedEntityIds)) {
$this->selectedEntityIds[$priorityKey] = [];
}
$this->selectedEntityIds[$priorityKey] = array_merge($this->selectedEntityIds[$priorityKey], $entityIds);
}
}
public function isEmpty(): bool
/**
* @return string[]
*/
public function getEntityListGroups(): array
{
{
return empty($this->priorityEntityIdList) && empty($this->normalEntityIdList);
return array_keys($this->selectedEntityIds);
}
}
public function getHighPriorityEntityIds(): array
public function getEntityListItemsByGroup(string|QueuePriorityEnum $priority): array
{
{
return $this->priorityEntityIdList;
$priorityKey = $this->normalisePriority($priority);
return $this->selectedEntityIds[$priorityKey] ?? [];
}
}
public function getNormalPriorityEntityId(): array
public function getAllIds(): array
{
{
return $this->normalEntityIdList;...
|
55691
|
NULL
|
NULL
|
NULL
|
|
55694
|
NULL
|
0
|
2026-05-19T06:41:19.120729+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779172879120_m2.jpg...
|
Firefox
|
JY-20808 low priority indexing queue by Vasil-Jimi JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app — Work...
|
1
|
github.com/jiminny/app/pull/12082/changes#diff-49a github.com/jiminny/app/pull/12082/changes#diff-49a79d99c97caf7fc27ecb1dbacab5a29d871822caa0db0c71e94957c28c87af...
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
Close tab
New Tab
Customize sidebar
Close Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
AI Chat settings
Close
WORK, Google Account: [EMAIL]
Main menu
New chat
Gemini
New Chat
Open menu for conversation actions.
Conversation with Gemini
Conversation with Gemini
Show the uploaded image in a lightbox
Copy prompt
You said Make a PR of changes Find potential issues and bottlenecks
You said
Make a PR of changes Find potential issues and bottlenecks
Listen
Show thinking
Gemini said
Gemini said
I can see you've uploaded a screenshot of a code diff, likely from a version control system given the red and green highlights. I would love to help you review the changes, spot bottlenecks, and help you draft a Pull Request.
However,
the image resolution is far too low for me to read.
It appears to be a completely zoomed-out view where the code has been reduced to tiny, illegible pixels. Because of this, I cannot extract any text or logic to analyze.
How You Can Share the Code
How You Can Share the Code
To help me review your code effectively, please try one of the following:
Paste the text directly:
Copy the specific code blocks (both the old and new versions if possible) and paste them directly into our chat.
Upload the files:
If the changes are extensive, you can upload the raw text or code files.
Take high-resolution screenshots:
If you must use images, take closer, readable screenshots of the specific functions or methods you want me to review.
Once you provide the readable code, I can dive right in to identify potential bugs, assess performance bottlenecks, and help you summarize the changes for your PR!
Good response
Bad response
Share & export
Copy
Show more options
Copy prompt
Edit
You said app/Component/ES/Listeners/UpdateMultipleTargetsListener.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\Component\ES\Listeners; namespace Jiminny\Component\ES\Listeners; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Contracts\ES\Events\UpdateMultipleEntities; use Jiminny\Contracts\ES\Events\UpdateMultipleEntities; use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface; AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntities(), $event->getEntities(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } } } app/Component/ES/Listeners/UpdateSingleTargetListener.php +9-1Lines changed: 9 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Actions\TrackElasticSearchOperations; use Jiminny\Component\ES\Actions\TrackElasticSearchOperations; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Contracts\ES\Events\UpdateSingleEntity; use Jiminny\Contracts\ES\Events\UpdateSingleEntity; use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface; 'entityId' => $event->getEntityId(), 'entityId' => $event->getEntityId(), ]); ]); /** * @important: * Synchronous event should eventually be deprecated. * Instant write operations are blocking and should be used sparingly. * It is much better in terms of performance to write 100 or 1000 documents at once, * and have one blocking reindex operation, instead of writing 10 documents synchronously. */ if ($event->isSyncEvent()) { if ($event->isSyncEvent()) { $this->handleSyncEvent($event); $this->handleSyncEvent($event); AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntityId(), $event->getEntityId(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } app/Component/ES/Processor/Actions/UpsertDocumentsAction.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SimpleCollection; use Jiminny\Component\ES\Processor\DTOs\SimpleCollection; use Jiminny\Component\ES\Processor\ResponseEvaluator; use Jiminny\Component\ES\Processor\ResponseEvaluator; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Exceptions\InvalidDataException; use Jiminny\Exceptions\InvalidDataException; use Sentry\Laravel\Facade as Sentry; use Sentry\Laravel\Facade as Sentry; AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( entityType: $this->updateTarget, entityType: $this->updateTarget, entityId: (int) $document->getId(), entityId: (int) $document->getId(), withPriority: true priority: QueuePriorityEnum::HIGH, ); ); } } app/Component/ES/Processor/DTOs/SelectionList.php +54-17Lines changed: 54 additions & 17 deletions Original file line numberOriginal file lineDiff line numberDiff line change namespace Jiminny\Component\ES\Processor\DTOs; namespace Jiminny\Component\ES\Processor\DTOs; use Jiminny\Component\ES\QueuePriorityEnum; /** /** * A very basic and simple collection of entity IDs. * A very basic and simple collection of entity IDs. */ */ class SelectionList class SelectionList { { public function __construct( private const int DEFAULT_CHUNK = 200; private readonly array $priorityEntityIdList = [], private readonly array $normalEntityIdList = [], private int $chunkSize = self::DEFAULT_CHUNK; private readonly bool $isStaleChunkSelected = false, private bool $isStaleChunkSelected = false; private readonly int $chunkSize = 200, private array $selectedEntityIds = []; ) { // Do nothing public function setChunkSize(int $chunkSize): void { $this->chunkSize = $chunkSize; } } public function getAllIds(): array public function markStale(): void { { return array_merge($this->priorityEntityIdList, $this->normalEntityIdList); $this->isStaleChunkSelected = true; } } public function count(): int public function addEntityList(string|QueuePriorityEnum $priority, array $entityIds): void { { return count($this->priorityEntityIdList) + count($this->normalEntityIdList); $priorityKey = $this->normalisePriority($priority); if (! array_key_exists($priorityKey, $this->selectedEntityIds)) { $this->selectedEntityIds[$priorityKey] = []; } $this->selectedEntityIds[$priorityKey] = array_merge($this->selectedEntityIds[$priorityKey], $entityIds); } } public function isEmpty(): bool /** * @return string[] */ public function getEntityListGroups(): array { { return empty($this->priorityEntityIdList) && empty($this->normalEntityIdList); return array_keys($this->selectedEntityIds); } } public function getHighPriorityEntityIds(): array public function getEntityListItemsByGroup(string|QueuePriorityEnum $priority): array { { return $this->priorityEntityIdList; $priorityKey = $this->normalisePriority($priority); return $this->selectedEntityIds[$priorityKey] ?? []; } } public function getNormalPriorityEntityId(): array public function getAllIds(): array { { return $this->normalEntityIdList; $allIds = []; foreach ($this->selectedEntityIds as $entityIds) { $allIds = array_merge($allIds, $entityIds); } return $allIds; } public function count(): int { return array_sum( array_map('count', $this->selectedEntityIds) ); } public function isEmpty(): bool { return $this->count() === 0; } } public function isStaleChunkSelected(): bool public function isStaleChunkSelected(): bool { { return $this->count() >= $this->chunkSize; return $this->count() >= $this->chunkSize; } } private function normalisePriority(string|QueuePriorityEnum $priority): string { return $priority instanceof QueuePriorityEnum ? $priority->value : $priority; } } } app/Component/ES/Processor/Traits/SelectEntityListTrait.php +27-4Lines changed: 27 additions & 4 deletions Original file line numberOriginal file lineDiff line numberDiff line change use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; /** /** * Build the correct source list name for the type of entity and priority * Build the correct source list name for the type of entity and priority */ */ trait SelectEntityListTrait trait SelectEntityListTrait { { /** * Highest priority queue for data requiring near-instant availability. * Very few entities should be added here, only when absolutely necessary. */ private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; /** * Normal priority queue for normal application operations. * Almost all update events should pass through this queue */ private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; protected static function selectTargetList(string $entityType, bool $withPriority = false): string /** { * Nonblocking low priority queue. This queue will be consumed only when there is nothing * with higher priority. * * This queue will be used for operations such as es:reset-async */ private const string ENTITIES_LOW_PRIORITIES_LIST = '%s-for-update-low'; protected static function selectTargetList( string $entityType, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { if (! in_array($entityType, UpdateTarget::allowedTargets())) { if (! in_array($entityType, UpdateTarget::allowedTargets())) { throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); } } if ($withPriority) { if ($priority->isHigh()) { Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); } } if ($priority->isLow()) { return sprintf(self::ENTITIES_LOW_PRIORITIES_LIST, $entityType); } return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); } } } } app/Component/ES/Processor/TargetEntitiesSelector.php +26-21Lines changed: 26 additions & 21 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SelectionList; use Jiminny\Component\ES\Processor\DTOs\SelectionList; use Jiminny\Component\ES\Processor\Traits\ExtractIdsTrait; use Jiminny\Component\ES\Processor\Traits\ExtractIdsTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\QueuePriorityEnum; /** /** * This class supplies a list of entities pending an update. * This class supplies a list of entities pending an update. public function select(): SelectionList public function select(): SelectionList { { $staleWorkEntityIds = $this->getStaleChunk(); $selectionList = new SelectionList(); $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $staleWorkEntityIds = $this->getStaleChunk(); if (count($staleWorkEntityIds) > 0) { if (count($staleWorkEntityIds) > 0) { return new SelectionList( /** priorityEntityIdList: $staleWorkEntityIds, * Stale chunks are treated as high priority isStaleChunkSelected: true, */ chunkSize: ChunkSize::getStaleChunkSize($this->updateTarget), $selectionList->markStale(); ); $selectionList->addEntityList(QueuePriorityEnum::HIGH, $staleWorkEntityIds); $selectionList->setChunkSize(ChunkSize::getStaleChunkSize($this->updateTarget)); return $selectionList; } } $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $selectionList->setChunkSize($mainChunkSize); $priorityEntityIdsList = $this->extractIdsFromSet( $priorityEntityIdsList = $this->extractIds(QueuePriorityEnum::HIGH, $mainChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, true), $selectionList->addEntityList(QueuePriorityEnum::HIGH, $priorityEntityIdsList); $mainChunkSize, ); $normalEntityIdsList = []; $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); if ($normalEntityChunkSize > 0) { if ($normalEntityChunkSize > 0) { $normalEntityIdsList = $this->extractIdsFromSet( $normalEntityIdsList = $this->extractIds(QueuePriorityEnum::NORMAL, $normalEntityChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, false), $selectionList->addEntityList(QueuePriorityEnum::NORMAL, $normalEntityIdsList); $normalEntityChunkSize ); } } return new SelectionList( return $selectionList; priorityEntityIdList: $priorityEntityIdsList, normalEntityIdList: $normalEntityIdsList, chunkSize: $mainChunkSize ); } } private function getStaleChunk(): array private function getStaleChunk(): array return []; return []; } } private function extractIds(QueuePriorityEnum $priority, int $chunkSize): array { return $this->extractIdsFromSet( AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, $priority), $chunkSize ); } } } app/Component/ES/AsyncUpdateElasticSearch.php +17-10Lines changed: 17 additions & 10 deletions Original file line numberOriginal file lineDiff line numberDiff line change * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * and other activity related data * and other activity related data */ */ public static function markEntityForUpdate(string $entityType, int $entityId, bool $withPriority = false): void public static function markEntityForUpdate( { string $entityType, $targetList = self::selectTargetList($entityType, $withPriority); int $entityId, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { $targetList = self::selectTargetList($entityType, $priority); Redis::sadd($targetList, $entityId); Redis::sadd($targetList, $entityId); Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ 'entityType' => $entityType, 'entityType' => $entityType, 'entityId' => $entityId, 'entityId' => $entityId, 'collectionKey' => $targetList, 'collectionKey' => $targetList, 'withPriority' => $withPriority, 'priority' => $priority->value, ]); ]); } } public static function bulkMarkEntitiesForUpdate( public static function bulkMarkEntitiesForUpdate( string $entityType, string $entityType, array $entityIds, array $entityIds, bool $withPriority = false QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { ): void { if (empty($entityIds)) { if (empty($entityIds)) { return; return; } } $targetList = self::selectTargetList($entityType, $withPriority); $targetList = self::selectTargetList($entityType, $priority); Redis::saddarray($targetList, $entityIds); Redis::saddarray($targetList, $entityIds); } } * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Takes priority into consideration. * Takes priority into consideration. */ */ public static function getEntitiesSourceList(string $updateTarget, $priority = false): string public static function getEntitiesSourceList( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { return self::selectTargetList($updateTarget, $priority); return self::selectTargetList($updateTarget, $priority); } } /** /** * Externally called helper methods * Externally called helper methods * - count and flush * - count and flush */ */ public static function getEntitiesListCount(string $updateTarget, $priority = false): int public static function getEntitiesListCount( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): int { $targetList = self::selectTargetList($updateTarget, $priority); $targetList = self::selectTargetList($updateTarget, $priority); return Redis::scard($targetList); return Redis::scard($targetList); app/Component/ES/QueuePriorityEnum.php +40Lines changed: 40 additions & 0 deletions Original file line numberOriginal file lineDiff line numberDiff line change <?php declare(strict_types=1); namespace Jiminny\Component\ES; use Jiminny\Exceptions\InvalidArgumentException; enum QueuePriorityEnum: string { case HIGH = 'high'; case NORMAL = 'normal'; case LOW = 'low'; public static function tryFromString(string $value): self { if (! self::isValid($value)) { throw new InvalidArgumentException( sprintf('Invalid queue priority "%s" selected', $value) ); } return self::tryFrom($value); } public static function isValid(string $value): bool { return self::tryFrom($value) !== null; } public function isLow(): bool { return $this === self::LOW; } public function isHigh(): bool { return $this === self::HIGH; } } app/Component/ES/UpdateProcessManager.php +12-9Lines changed: 12 additions & 9 deletions Original file line numberOriginal file lineDiff line numberDiff line change if ($selectionList->isEmpty()) { if ($selectionList->isEmpty()) { return false; return false; } } /** /** * A stale chunk will always be smaller than a regular chunk. * A stale chunk will always be smaller than a regular chunk. * That doesn't mean there aren't any other scheduled entities for processing * That doesn't mean there aren't any other scheduled entities for processing private function rescheduleThrottledEntities(SelectionList $selectionList): void private function rescheduleThrottledEntities(SelectionList $selectionList): void { { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $groups = $selectionList->getEntityListGroups(); $this->updateTarget, foreach ($groups as $eachGroup) { $selectionList->getNormalPriorityEntityId() $groupEntityIds = $selectionList->getEntityListItemsByGroup($eachGroup); ); if (! empty($groupEntityIds)) { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $this->updateTarget, entityType: $this->updateTarget, $selectionList->getHighPriorityEntityIds(), entityIds: $groupEntityIds, true priority: QueuePriorityEnum::tryFromString($eachGroup) ); ); } } } } } } app/Console/Commands/Elasticsearch/AsyncUpdateEsEntities.php +9-3Lines changed: 9 additions & 3 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Illuminate\Support\Str; use Illuminate\Support\Str; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Component\ES\UpdateProcessManager; use Jiminny\Component\ES\UpdateProcessManager; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Traits\GracefullyStoppable; use Jiminny\Traits\GracefullyStoppable; Redis::set($gaugeLockName, true); Redis::set($gaugeLockName, true); Redis::expire($gaugeLockName, 60); Redis::expire($gaugeLockName, 60); $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::HIGH), ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update', $updateTarget), stat: sprintf('jiminny.%s-for-update', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::NORMAL), ); ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), stat: sprintf('jiminny.%s-for-update-low', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, true), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::LOW), ); ); } } app/Console/Commands/Elasticsearch/ResetAsyncElasticSearchCommand.php +5-1Lines changed: 5 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\Traits\ValidateUpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\ValidateUpdateTargetTrait; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Component\ES\Repositories\EsResetRepositoryInterface; use Jiminny\Component\ES\Repositories\EsResetRepositoryInterface; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Traits\GracefullyStoppable; use Jiminny\Traits\GracefullyStoppable; private function getRemainingScheduledEntities(bool $printStatus = false): int private function getRemainingScheduledEntities(bool $printStatus = false): int { { $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget, true); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount( $this->updateTarget, QueuePriorityEnum::HIGH ); if ($printStatus) { if ($printStatus) { $this->line( $this->line(
You said
app/Component/ES/Listeners/UpdateMultipleTargetsListener.php
+2-1Lines changed: 2 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\Component\ES\Listeners;
namespace Jiminny\Component\ES\Listeners;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\QueuePriorityEnum;
use Jiminny\Contracts\ES\Events\UpdateMultipleEntities;
use Jiminny\Contracts\ES\Events\UpdateMultipleEntities;
use Psr\Log\LoggerInterface;
use Psr\Log\LoggerInterface;
AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(
AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(
$event->getUpdateTargetValue(),
$event->getUpdateTargetValue(),
$event->getEntities(),
$event->getEntities(),
$event->isPriority()
$event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL,
);
);
}
}
}
}
app/Component/ES/Listeners/UpdateSingleTargetListener.php
+9-1Lines changed: 9 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Actions\TrackElasticSearchOperations;
use Jiminny\Component\ES\Actions\TrackElasticSearchOperations;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\Processor\EntityQueryBuilder;
use Jiminny\Component\ES\Processor\EntityQueryBuilder;
use Jiminny\Component\ES\QueuePriorityEnum;
use Jiminny\Contracts\ES\Events\UpdateSingleEntity;
use Jiminny\Contracts\ES\Events\UpdateSingleEntity;
use Psr\Log\LoggerInterface;
use Psr\Log\LoggerInterface;
'entityId' => $event->getEntityId(),
'entityId' => $event->getEntityId(),
]);
]);
/**
* @important:
* Synchronous event should eventually be deprecated.
* Instant write operations are blocking and should be used sparingly.
* It is much better in terms of performance to write 100 or 1000 documents at once,
* and have one blocking reindex operation, instead of writing 10 documents synchronously.
*/
if ($event->isSyncEvent()) {
if ($event->isSyncEvent()) {
$this->handleSyncEvent($event);
$this->handleSyncEvent($event);
AsyncUpdateElasticSearch::markEntityForUpdate(
AsyncUpdateElasticSearch::markEntityForUpdate(
$event->getUpdateTargetValue(),
$event->getUpdateTargetValue(),
$event->getEntityId(),
$event->getEntityId(),
$event->isPriority()
$event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL,
);
);
}
}
app/Component/ES/Processor/Actions/UpsertDocumentsAction.php
+2-1Lines changed: 2 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SimpleCollection;
use Jiminny\Component\ES\Processor\DTOs\SimpleCollection;
use Jiminny\Component\ES\Processor\ResponseEvaluator;
use Jiminny\Component\ES\Processor\ResponseEvaluator;
use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait;
use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait;
use Jiminny\Component\ES\QueuePriorityEnum;
use Jiminny\Exceptions\InvalidDataException;
use Jiminny\Exceptions\InvalidDataException;
use Sentry\Laravel\Facade as Sentry;
use Sentry\Laravel\Facade as Sentry;
AsyncUpdateElasticSearch::markEntityForUpdate(
AsyncUpdateElasticSearch::markEntityForUpdate(
entityType: $this->updateTarget,
entityType: $this->updateTarget,
entityId: (int) $document->getId(),
entityId: (int) $document->getId(),
withPriority: true
priority: QueuePriorityEnum::HIGH,
);
);
}
}
app/Component/ES/Processor/DTOs/SelectionList.php
+54-17Lines changed: 54 additions & 17 deletions
Original file line numberOriginal file lineDiff line numberDiff line change
namespace Jiminny\Component\ES\Processor\DTOs;
namespace Jiminny\Component\ES\Processor\DTOs;
use Jiminny\Component\ES\QueuePriorityEnum;
/**
/**
* A very basic and simple collection of entity IDs.
* A very basic and simple collection of entity IDs.
*/
*/
class SelectionList
class SelectionList
{
{
public function __construct(
private const int DEFAULT_CHUNK = 200;
private readonly array $priorityEntityIdList = [],
private readonly array $normalEntityIdList = [],
private int $chunkSize = self::DEFAULT_CHUNK;
private readonly bool $isStaleChunkSelected = false,
private bool $isStaleChunkSelected = false;
private readonly int $chunkSize = 200,
private array $selectedEntityIds = [];
) {
// Do nothing
public function setChunkSize(int $chunkSize): void
{
$this->chunkSize = $chunkSize;
}
}...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira","depth":4,"bounds":{"left":0.0,"top":0.0518755,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.06304868,"width":0.10106383,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app","depth":4,"bounds":{"left":0.0,"top":0.08459697,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app","depth":5,"bounds":{"left":0.013297873,"top":0.09577015,"width":0.18816489,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app","depth":4,"bounds":{"left":0.0,"top":0.11731844,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app","depth":5,"bounds":{"left":0.013297873,"top":0.12849163,"width":0.15674867,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.06732048,"top":0.1245012,"width":0.007978723,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New Tab","depth":4,"bounds":{"left":0.0028257978,"top":0.15163608,"width":0.07413564,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"bounds":{"left":0.0028257978,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Close Google Gemini (⌃X)","depth":6,"bounds":{"left":0.013796543,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Tabs from other devices","depth":6,"bounds":{"left":0.024933511,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"bounds":{"left":0.036070477,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"bounds":{"left":0.04720745,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"AI Chat settings","depth":7,"bounds":{"left":0.35854387,"top":0.055067837,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Close","depth":7,"bounds":{"left":0.37051198,"top":0.055067837,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"WORK, Google Account: lukas.kovalik@jiminny.com","depth":12,"bounds":{"left":0.3678524,"top":0.103751,"width":0.013297873,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Main menu","depth":12,"bounds":{"left":0.08494016,"top":0.103751,"width":0.013297873,"height":0.031923383},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New chat","depth":12,"bounds":{"left":0.09823803,"top":0.10454908,"width":0.028590426,"height":0.030327214},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Gemini","depth":15,"bounds":{"left":0.1008976,"top":0.10973663,"width":0.021941489,"height":0.020351157},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"New Chat","depth":12,"bounds":{"left":0.33992687,"top":0.103751,"width":0.013297873,"height":0.031923383},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Open menu for conversation actions.","depth":12,"bounds":{"left":0.35322472,"top":0.103751,"width":0.013297873,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXHeading","text":"Conversation with Gemini","depth":15,"bounds":{"left":0.079288565,"top":0.14764565,"width":0.0003324468,"height":0.0007980846},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Conversation with Gemini","depth":16,"bounds":{"left":0.079288565,"top":0.15003991,"width":0.1200133,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Show the uploaded image in a lightbox","depth":21,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy prompt","depth":21,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"You said Make a PR of changes Find potential issues and bottlenecks","depth":21,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"You said","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Make a PR of changes Find potential issues and bottlenecks","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Listen","depth":22,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Show thinking","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Gemini said","depth":20,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Gemini said","depth":21,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"I can see you've uploaded a screenshot of a code diff, likely from a version control system given the red and green highlights. I would love to help you review the changes, spot bottlenecks, and help you draft a Pull Request.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"However,","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"the image resolution is far too low for me to read.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"It appears to be a completely zoomed-out view where the code has been reduced to tiny, illegible pixels. Because of this, I cannot extract any text or logic to analyze.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"How You Can Share the Code","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"How You Can Share the Code","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"To help me review your code effectively, please try one of the following:","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Paste the text directly:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Copy the specific code blocks (both the old and new versions if possible) and paste them directly into our chat.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Upload the files:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"If the changes are extensive, you can upload the raw text or code files.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Take high-resolution screenshots:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"If you must use images, take closer, readable screenshots of the specific functions or methods you want me to review.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Once you provide the readable code, I can dive right in to identify potential bugs, assess performance bottlenecks, and help you summarize the changes for your PR!","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Good response","depth":22,"on_screen":false,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Bad response","depth":22,"on_screen":false,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Share & export","depth":21,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy","depth":22,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Show more options","depth":21,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy prompt","depth":21,"bounds":{"left":0.17121011,"top":0.0,"width":0.013297873,"height":0.031923383},"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Edit","depth":21,"bounds":{"left":0.18583776,"top":0.0,"width":0.013297873,"height":0.031923383},"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"You said app/Component/ES/Listeners/UpdateMultipleTargetsListener.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\\Component\\ES\\Listeners; namespace Jiminny\\Component\\ES\\Listeners; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Contracts\\ES\\Events\\UpdateMultipleEntities; use Jiminny\\Contracts\\ES\\Events\\UpdateMultipleEntities; use Psr\\Log\\LoggerInterface; use Psr\\Log\\LoggerInterface; AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntities(), $event->getEntities(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } } } app/Component/ES/Listeners/UpdateSingleTargetListener.php +9-1Lines changed: 9 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Actions\\TrackElasticSearchOperations; use Jiminny\\Component\\ES\\Actions\\TrackElasticSearchOperations; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder; use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Contracts\\ES\\Events\\UpdateSingleEntity; use Jiminny\\Contracts\\ES\\Events\\UpdateSingleEntity; use Psr\\Log\\LoggerInterface; use Psr\\Log\\LoggerInterface; 'entityId' => $event->getEntityId(), 'entityId' => $event->getEntityId(), ]); ]); /** * @important: * Synchronous event should eventually be deprecated. * Instant write operations are blocking and should be used sparingly. * It is much better in terms of performance to write 100 or 1000 documents at once, * and have one blocking reindex operation, instead of writing 10 documents synchronously. */ if ($event->isSyncEvent()) { if ($event->isSyncEvent()) { $this->handleSyncEvent($event); $this->handleSyncEvent($event); AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntityId(), $event->getEntityId(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } app/Component/ES/Processor/Actions/UpsertDocumentsAction.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Processor\\DTOs\\SimpleCollection; use Jiminny\\Component\\ES\\Processor\\DTOs\\SimpleCollection; use Jiminny\\Component\\ES\\Processor\\ResponseEvaluator; use Jiminny\\Component\\ES\\Processor\\ResponseEvaluator; use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait; use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Exceptions\\InvalidDataException; use Jiminny\\Exceptions\\InvalidDataException; use Sentry\\Laravel\\Facade as Sentry; use Sentry\\Laravel\\Facade as Sentry; AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( entityType: $this->updateTarget, entityType: $this->updateTarget, entityId: (int) $document->getId(), entityId: (int) $document->getId(), withPriority: true priority: QueuePriorityEnum::HIGH, ); ); } } app/Component/ES/Processor/DTOs/SelectionList.php +54-17Lines changed: 54 additions & 17 deletions Original file line numberOriginal file lineDiff line numberDiff line change namespace Jiminny\\Component\\ES\\Processor\\DTOs; namespace Jiminny\\Component\\ES\\Processor\\DTOs; use Jiminny\\Component\\ES\\QueuePriorityEnum; /** /** * A very basic and simple collection of entity IDs. * A very basic and simple collection of entity IDs. */ */ class SelectionList class SelectionList { { public function __construct( private const int DEFAULT_CHUNK = 200; private readonly array $priorityEntityIdList = [], private readonly array $normalEntityIdList = [], private int $chunkSize = self::DEFAULT_CHUNK; private readonly bool $isStaleChunkSelected = false, private bool $isStaleChunkSelected = false; private readonly int $chunkSize = 200, private array $selectedEntityIds = []; ) { // Do nothing public function setChunkSize(int $chunkSize): void { $this->chunkSize = $chunkSize; } } public function getAllIds(): array public function markStale(): void { { return array_merge($this->priorityEntityIdList, $this->normalEntityIdList); $this->isStaleChunkSelected = true; } } public function count(): int public function addEntityList(string|QueuePriorityEnum $priority, array $entityIds): void { { return count($this->priorityEntityIdList) + count($this->normalEntityIdList); $priorityKey = $this->normalisePriority($priority); if (! array_key_exists($priorityKey, $this->selectedEntityIds)) { $this->selectedEntityIds[$priorityKey] = []; } $this->selectedEntityIds[$priorityKey] = array_merge($this->selectedEntityIds[$priorityKey], $entityIds); } } public function isEmpty(): bool /** * @return string[] */ public function getEntityListGroups(): array { { return empty($this->priorityEntityIdList) && empty($this->normalEntityIdList); return array_keys($this->selectedEntityIds); } } public function getHighPriorityEntityIds(): array public function getEntityListItemsByGroup(string|QueuePriorityEnum $priority): array { { return $this->priorityEntityIdList; $priorityKey = $this->normalisePriority($priority); return $this->selectedEntityIds[$priorityKey] ?? []; } } public function getNormalPriorityEntityId(): array public function getAllIds(): array { { return $this->normalEntityIdList; $allIds = []; foreach ($this->selectedEntityIds as $entityIds) { $allIds = array_merge($allIds, $entityIds); } return $allIds; } public function count(): int { return array_sum( array_map('count', $this->selectedEntityIds) ); } public function isEmpty(): bool { return $this->count() === 0; } } public function isStaleChunkSelected(): bool public function isStaleChunkSelected(): bool { { return $this->count() >= $this->chunkSize; return $this->count() >= $this->chunkSize; } } private function normalisePriority(string|QueuePriorityEnum $priority): string { return $priority instanceof QueuePriorityEnum ? $priority->value : $priority; } } } app/Component/ES/Processor/Traits/SelectEntityListTrait.php +27-4Lines changed: 27 additions & 4 deletions Original file line numberOriginal file lineDiff line numberDiff line change use Illuminate\\Support\\Facades\\Log; use Illuminate\\Support\\Facades\\Log; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Exceptions\\InvalidArgumentException; use Jiminny\\Exceptions\\InvalidArgumentException; /** /** * Build the correct source list name for the type of entity and priority * Build the correct source list name for the type of entity and priority */ */ trait SelectEntityListTrait trait SelectEntityListTrait { { /** * Highest priority queue for data requiring near-instant availability. * Very few entities should be added here, only when absolutely necessary. */ private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; /** * Normal priority queue for normal application operations. * Almost all update events should pass through this queue */ private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; protected static function selectTargetList(string $entityType, bool $withPriority = false): string /** { * Nonblocking low priority queue. This queue will be consumed only when there is nothing * with higher priority. * * This queue will be used for operations such as es:reset-async */ private const string ENTITIES_LOW_PRIORITIES_LIST = '%s-for-update-low'; protected static function selectTargetList( string $entityType, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { if (! in_array($entityType, UpdateTarget::allowedTargets())) { if (! in_array($entityType, UpdateTarget::allowedTargets())) { throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); } } if ($withPriority) { if ($priority->isHigh()) { Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); } } if ($priority->isLow()) { return sprintf(self::ENTITIES_LOW_PRIORITIES_LIST, $entityType); } return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); } } } } app/Component/ES/Processor/TargetEntitiesSelector.php +26-21Lines changed: 26 additions & 21 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Processor\\DTOs\\SelectionList; use Jiminny\\Component\\ES\\Processor\\DTOs\\SelectionList; use Jiminny\\Component\\ES\\Processor\\Traits\\ExtractIdsTrait; use Jiminny\\Component\\ES\\Processor\\Traits\\ExtractIdsTrait; use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait; use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait; use Jiminny\\Component\\ES\\QueuePriorityEnum; /** /** * This class supplies a list of entities pending an update. * This class supplies a list of entities pending an update. public function select(): SelectionList public function select(): SelectionList { { $staleWorkEntityIds = $this->getStaleChunk(); $selectionList = new SelectionList(); $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $staleWorkEntityIds = $this->getStaleChunk(); if (count($staleWorkEntityIds) > 0) { if (count($staleWorkEntityIds) > 0) { return new SelectionList( /** priorityEntityIdList: $staleWorkEntityIds, * Stale chunks are treated as high priority isStaleChunkSelected: true, */ chunkSize: ChunkSize::getStaleChunkSize($this->updateTarget), $selectionList->markStale(); ); $selectionList->addEntityList(QueuePriorityEnum::HIGH, $staleWorkEntityIds); $selectionList->setChunkSize(ChunkSize::getStaleChunkSize($this->updateTarget)); return $selectionList; } } $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $selectionList->setChunkSize($mainChunkSize); $priorityEntityIdsList = $this->extractIdsFromSet( $priorityEntityIdsList = $this->extractIds(QueuePriorityEnum::HIGH, $mainChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, true), $selectionList->addEntityList(QueuePriorityEnum::HIGH, $priorityEntityIdsList); $mainChunkSize, ); $normalEntityIdsList = []; $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); if ($normalEntityChunkSize > 0) { if ($normalEntityChunkSize > 0) { $normalEntityIdsList = $this->extractIdsFromSet( $normalEntityIdsList = $this->extractIds(QueuePriorityEnum::NORMAL, $normalEntityChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, false), $selectionList->addEntityList(QueuePriorityEnum::NORMAL, $normalEntityIdsList); $normalEntityChunkSize ); } } return new SelectionList( return $selectionList; priorityEntityIdList: $priorityEntityIdsList, normalEntityIdList: $normalEntityIdsList, chunkSize: $mainChunkSize ); } } private function getStaleChunk(): array private function getStaleChunk(): array return []; return []; } } private function extractIds(QueuePriorityEnum $priority, int $chunkSize): array { return $this->extractIdsFromSet( AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, $priority), $chunkSize ); } } } app/Component/ES/AsyncUpdateElasticSearch.php +17-10Lines changed: 17 additions & 10 deletions Original file line numberOriginal file lineDiff line numberDiff line change * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * and other activity related data * and other activity related data */ */ public static function markEntityForUpdate(string $entityType, int $entityId, bool $withPriority = false): void public static function markEntityForUpdate( { string $entityType, $targetList = self::selectTargetList($entityType, $withPriority); int $entityId, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { $targetList = self::selectTargetList($entityType, $priority); Redis::sadd($targetList, $entityId); Redis::sadd($targetList, $entityId); Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ 'entityType' => $entityType, 'entityType' => $entityType, 'entityId' => $entityId, 'entityId' => $entityId, 'collectionKey' => $targetList, 'collectionKey' => $targetList, 'withPriority' => $withPriority, 'priority' => $priority->value, ]); ]); } } public static function bulkMarkEntitiesForUpdate( public static function bulkMarkEntitiesForUpdate( string $entityType, string $entityType, array $entityIds, array $entityIds, bool $withPriority = false QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { ): void { if (empty($entityIds)) { if (empty($entityIds)) { return; return; } } $targetList = self::selectTargetList($entityType, $withPriority); $targetList = self::selectTargetList($entityType, $priority); Redis::saddarray($targetList, $entityIds); Redis::saddarray($targetList, $entityIds); } } * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Takes priority into consideration. * Takes priority into consideration. */ */ public static function getEntitiesSourceList(string $updateTarget, $priority = false): string public static function getEntitiesSourceList( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { return self::selectTargetList($updateTarget, $priority); return self::selectTargetList($updateTarget, $priority); } } /** /** * Externally called helper methods * Externally called helper methods * - count and flush * - count and flush */ */ public static function getEntitiesListCount(string $updateTarget, $priority = false): int public static function getEntitiesListCount( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): int { $targetList = self::selectTargetList($updateTarget, $priority); $targetList = self::selectTargetList($updateTarget, $priority); return Redis::scard($targetList); return Redis::scard($targetList); app/Component/ES/QueuePriorityEnum.php +40Lines changed: 40 additions & 0 deletions Original file line numberOriginal file lineDiff line numberDiff line change <?php declare(strict_types=1); namespace Jiminny\\Component\\ES; use Jiminny\\Exceptions\\InvalidArgumentException; enum QueuePriorityEnum: string { case HIGH = 'high'; case NORMAL = 'normal'; case LOW = 'low'; public static function tryFromString(string $value): self { if (! self::isValid($value)) { throw new InvalidArgumentException( sprintf('Invalid queue priority \"%s\" selected', $value) ); } return self::tryFrom($value); } public static function isValid(string $value): bool { return self::tryFrom($value) !== null; } public function isLow(): bool { return $this === self::LOW; } public function isHigh(): bool { return $this === self::HIGH; } } app/Component/ES/UpdateProcessManager.php +12-9Lines changed: 12 additions & 9 deletions Original file line numberOriginal file lineDiff line numberDiff line change if ($selectionList->isEmpty()) { if ($selectionList->isEmpty()) { return false; return false; } } /** /** * A stale chunk will always be smaller than a regular chunk. * A stale chunk will always be smaller than a regular chunk. * That doesn't mean there aren't any other scheduled entities for processing * That doesn't mean there aren't any other scheduled entities for processing private function rescheduleThrottledEntities(SelectionList $selectionList): void private function rescheduleThrottledEntities(SelectionList $selectionList): void { { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $groups = $selectionList->getEntityListGroups(); $this->updateTarget, foreach ($groups as $eachGroup) { $selectionList->getNormalPriorityEntityId() $groupEntityIds = $selectionList->getEntityListItemsByGroup($eachGroup); ); if (! empty($groupEntityIds)) { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $this->updateTarget, entityType: $this->updateTarget, $selectionList->getHighPriorityEntityIds(), entityIds: $groupEntityIds, true priority: QueuePriorityEnum::tryFromString($eachGroup) ); ); } } } } } } app/Console/Commands/Elasticsearch/AsyncUpdateEsEntities.php +9-3Lines changed: 9 additions & 3 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Illuminate\\Support\\Str; use Illuminate\\Support\\Str; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Component\\ES\\UpdateProcessManager; use Jiminny\\Component\\ES\\UpdateProcessManager; use Jiminny\\Exceptions\\InvalidArgumentException; use Jiminny\\Exceptions\\InvalidArgumentException; use Jiminny\\Traits\\GracefullyStoppable; use Jiminny\\Traits\\GracefullyStoppable; Redis::set($gaugeLockName, true); Redis::set($gaugeLockName, true); Redis::expire($gaugeLockName, 60); Redis::expire($gaugeLockName, 60); $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::HIGH), ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update', $updateTarget), stat: sprintf('jiminny.%s-for-update', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::NORMAL), ); ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), stat: sprintf('jiminny.%s-for-update-low', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, true), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::LOW), ); ); } } app/Console/Commands/Elasticsearch/ResetAsyncElasticSearchCommand.php +5-1Lines changed: 5 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder; use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder; use Jiminny\\Component\\ES\\Processor\\Traits\\ValidateUpdateTargetTrait; use Jiminny\\Component\\ES\\Processor\\Traits\\ValidateUpdateTargetTrait; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Component\\ES\\Repositories\\EsResetRepositoryInterface; use Jiminny\\Component\\ES\\Repositories\\EsResetRepositoryInterface; use Jiminny\\Exceptions\\InvalidArgumentException; use Jiminny\\Exceptions\\InvalidArgumentException; use Jiminny\\Traits\\GracefullyStoppable; use Jiminny\\Traits\\GracefullyStoppable; private function getRemainingScheduledEntities(bool $printStatus = false): int private function getRemainingScheduledEntities(bool $printStatus = false): int { { $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget, true); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount( $this->updateTarget, QueuePriorityEnum::HIGH ); if ($printStatus) { if ($printStatus) { $this->line( $this->line(","depth":21,"bounds":{"left":0.20578457,"top":0.0,"width":0.13696809,"height":0.09577015},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"You said","depth":23,"bounds":{"left":0.079288565,"top":0.0,"width":0.019946808,"height":0.016360734},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app/Component/ES/Listeners/UpdateMultipleTargetsListener.php","depth":23,"bounds":{"left":0.20578457,"top":0.0,"width":0.084773935,"height":0.035514764},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"+2-1Lines changed: 2 additions & 1 deletion","depth":23,"bounds":{"left":0.20578457,"top":0.0007980846,"width":0.10388963,"height":0.016360734},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\\Component\\ES\\Listeners;","depth":23,"bounds":{"left":0.20578457,"top":0.039106146,"width":0.11303192,"height":0.054668795},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"namespace Jiminny\\Component\\ES\\Listeners;","depth":23,"bounds":{"left":0.20578457,"top":0.096568234,"width":0.1100399,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch;","depth":23,"bounds":{"left":0.20578457,"top":0.15403032,"width":0.13380983,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch;","depth":23,"bounds":{"left":0.20578457,"top":0.17318435,"width":0.13380983,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\QueuePriorityEnum;","depth":23,"bounds":{"left":0.20578457,"top":0.23064645,"width":0.115359046,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Contracts\\ES\\Events\\UpdateMultipleEntities;","depth":23,"bounds":{"left":0.20578457,"top":0.24980047,"width":0.13597074,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Contracts\\ES\\Events\\UpdateMultipleEntities;","depth":23,"bounds":{"left":0.20578457,"top":0.26895452,"width":0.13597074,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Psr\\Log\\LoggerInterface;","depth":23,"bounds":{"left":0.20578457,"top":0.28810853,"width":0.07047872,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Psr\\Log\\LoggerInterface;","depth":23,"bounds":{"left":0.20578457,"top":0.30726257,"width":0.07047872,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(","depth":23,"bounds":{"left":0.20578457,"top":0.36472467,"width":0.13530585,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(","depth":23,"bounds":{"left":0.20578457,"top":0.38387868,"width":0.13530585,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getUpdateTargetValue(),","depth":23,"bounds":{"left":0.20578457,"top":0.40303272,"width":0.0809508,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getUpdateTargetValue(),","depth":23,"bounds":{"left":0.20578457,"top":0.42218676,"width":0.0809508,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getEntities(),","depth":23,"bounds":{"left":0.20578457,"top":0.44134077,"width":0.052526597,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getEntities(),","depth":23,"bounds":{"left":0.20578457,"top":0.46049482,"width":0.052526597,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->isPriority()","depth":23,"bounds":{"left":0.20578457,"top":0.47964883,"width":0.046708778,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL,","depth":23,"bounds":{"left":0.20578457,"top":0.49880287,"width":0.11702128,"height":0.035514764},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":");","depth":23,"bounds":{"left":0.20578457,"top":0.5371109,"width":0.0033244682,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":");","depth":23,"bounds":{"left":0.20578457,"top":0.55626494,"width":0.0033244682,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"bounds":{"left":0.20578457,"top":0.575419,"width":0.0019946808,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"bounds":{"left":0.20578457,"top":0.594573,"width":0.0019946808,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"bounds":{"left":0.20578457,"top":0.61372703,"width":0.0019946808,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"bounds":{"left":0.20578457,"top":0.6328811,"width":0.0019946808,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app/Component/ES/Listeners/UpdateSingleTargetListener.php","depth":23,"bounds":{"left":0.20578457,"top":0.6520351,"width":0.07762633,"height":0.035514764},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"+9-1Lines changed: 9 additions & 1 deletion","depth":23,"bounds":{"left":0.20578457,"top":0.7094972,"width":0.104222074,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Actions\\TrackElasticSearchOperations;","depth":23,"bounds":{"left":0.20578457,"top":0.74780524,"width":0.13480718,"height":0.073822826},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Actions\\TrackElasticSearchOperations;","depth":23,"bounds":{"left":0.20578457,"top":0.8244214,"width":0.13480718,"height":0.054668795},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch;","depth":23,"bounds":{"left":0.20578457,"top":0.8818835,"width":0.13380983,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch;","depth":23,"bounds":{"left":0.20578457,"top":0.9010375,"width":0.13380983,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder;","depth":23,"bounds":{"left":0.20578457,"top":0.9201915,"width":0.1306516,"height":0.035514764},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder;","depth":23,"bounds":{"left":0.20578457,"top":0.9584996,"width":0.1306516,"height":0.035514764},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\QueuePriorityEnum;","depth":23,"bounds":{"left":0.20578457,"top":1.0,"width":0.115359046,"height":-0.03511572},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Contracts\\ES\\Events\\UpdateSingleEntity;","depth":23,"bounds":{"left":0.20578457,"top":1.0,"width":0.12732713,"height":-0.05426979},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Contracts\\ES\\Events\\UpdateSingleEntity;","depth":23,"bounds":{"left":0.20578457,"top":1.0,"width":0.12732713,"height":-0.07342374},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Psr\\Log\\LoggerInterface;","depth":23,"bounds":{"left":0.20578457,"top":1.0,"width":0.07047872,"height":-0.092577815},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Psr\\Log\\LoggerInterface;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"'entityId' => $event->getEntityId(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"'entityId' => $event->getEntityId(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"]);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"]);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/**","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* @important:","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* Synchronous event should eventually be deprecated.","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* Instant write operations are blocking and should be used sparingly.","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* It is much better in terms of performance to write 100 or 1000 documents at once,","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* and have one blocking reindex operation, instead of writing 10 documents synchronously.","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"*/","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"if ($event->isSyncEvent()) {","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"if ($event->isSyncEvent()) {","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$this->handleSyncEvent($event);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$this->handleSyncEvent($event);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AsyncUpdateElasticSearch::markEntityForUpdate(","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AsyncUpdateElasticSearch::markEntityForUpdate(","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getUpdateTargetValue(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getUpdateTargetValue(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getEntityId(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getEntityId(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->isPriority()","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL,","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":");","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":");","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app/Component/ES/Processor/Actions/UpsertDocumentsAction.php","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"+2-1Lines changed: 2 additions & 1 deletion","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Processor\\DTOs\\SimpleCollection;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\DTOs\\SimpleCollection;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\ResponseEvaluator;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\ResponseEvaluator;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\QueuePriorityEnum;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Exceptions\\InvalidDataException;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Exceptions\\InvalidDataException;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Sentry\\Laravel\\Facade as Sentry;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Sentry\\Laravel\\Facade as Sentry;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AsyncUpdateElasticSearch::markEntityForUpdate(","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AsyncUpdateElasticSearch::markEntityForUpdate(","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"entityType: $this->updateTarget,","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"entityType: $this->updateTarget,","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"entityId: (int) $document->getId(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"entityId: (int) $document->getId(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"withPriority: true","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"priority: QueuePriorityEnum::HIGH,","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":");","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":");","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app/Component/ES/Processor/DTOs/SelectionList.php","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"+54-17Lines changed: 54 additions & 17 deletions","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Original file line numberOriginal file lineDiff line numberDiff line change","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"namespace Jiminny\\Component\\ES\\Processor\\DTOs;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"namespace Jiminny\\Component\\ES\\Processor\\DTOs;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\QueuePriorityEnum;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/**","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/**","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* A very basic and simple collection of entity IDs.","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* A very basic and simple collection of entity IDs.","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"*/","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"*/","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"class SelectionList","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"class SelectionList","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function __construct(","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private const int DEFAULT_CHUNK = 200;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private readonly array $priorityEntityIdList = [],","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private readonly array $normalEntityIdList = [],","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private int $chunkSize = self::DEFAULT_CHUNK;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private readonly bool $isStaleChunkSelected = false,","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private bool $isStaleChunkSelected = false;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private readonly int $chunkSize = 200,","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private array $selectedEntityIds = [];","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":") {","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"// Do nothing","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function setChunkSize(int $chunkSize): void","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$this->chunkSize = $chunkSize;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"}]...
|
504577837169412428
|
-1127563140626703218
|
click
|
accessibility
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
Close tab
New Tab
Customize sidebar
Close Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
AI Chat settings
Close
WORK, Google Account: [EMAIL]
Main menu
New chat
Gemini
New Chat
Open menu for conversation actions.
Conversation with Gemini
Conversation with Gemini
Show the uploaded image in a lightbox
Copy prompt
You said Make a PR of changes Find potential issues and bottlenecks
You said
Make a PR of changes Find potential issues and bottlenecks
Listen
Show thinking
Gemini said
Gemini said
I can see you've uploaded a screenshot of a code diff, likely from a version control system given the red and green highlights. I would love to help you review the changes, spot bottlenecks, and help you draft a Pull Request.
However,
the image resolution is far too low for me to read.
It appears to be a completely zoomed-out view where the code has been reduced to tiny, illegible pixels. Because of this, I cannot extract any text or logic to analyze.
How You Can Share the Code
How You Can Share the Code
To help me review your code effectively, please try one of the following:
Paste the text directly:
Copy the specific code blocks (both the old and new versions if possible) and paste them directly into our chat.
Upload the files:
If the changes are extensive, you can upload the raw text or code files.
Take high-resolution screenshots:
If you must use images, take closer, readable screenshots of the specific functions or methods you want me to review.
Once you provide the readable code, I can dive right in to identify potential bugs, assess performance bottlenecks, and help you summarize the changes for your PR!
Good response
Bad response
Share & export
Copy
Show more options
Copy prompt
Edit
You said app/Component/ES/Listeners/UpdateMultipleTargetsListener.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\Component\ES\Listeners; namespace Jiminny\Component\ES\Listeners; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Contracts\ES\Events\UpdateMultipleEntities; use Jiminny\Contracts\ES\Events\UpdateMultipleEntities; use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface; AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntities(), $event->getEntities(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } } } app/Component/ES/Listeners/UpdateSingleTargetListener.php +9-1Lines changed: 9 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Actions\TrackElasticSearchOperations; use Jiminny\Component\ES\Actions\TrackElasticSearchOperations; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Contracts\ES\Events\UpdateSingleEntity; use Jiminny\Contracts\ES\Events\UpdateSingleEntity; use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface; 'entityId' => $event->getEntityId(), 'entityId' => $event->getEntityId(), ]); ]); /** * @important: * Synchronous event should eventually be deprecated. * Instant write operations are blocking and should be used sparingly. * It is much better in terms of performance to write 100 or 1000 documents at once, * and have one blocking reindex operation, instead of writing 10 documents synchronously. */ if ($event->isSyncEvent()) { if ($event->isSyncEvent()) { $this->handleSyncEvent($event); $this->handleSyncEvent($event); AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntityId(), $event->getEntityId(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } app/Component/ES/Processor/Actions/UpsertDocumentsAction.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SimpleCollection; use Jiminny\Component\ES\Processor\DTOs\SimpleCollection; use Jiminny\Component\ES\Processor\ResponseEvaluator; use Jiminny\Component\ES\Processor\ResponseEvaluator; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Exceptions\InvalidDataException; use Jiminny\Exceptions\InvalidDataException; use Sentry\Laravel\Facade as Sentry; use Sentry\Laravel\Facade as Sentry; AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( entityType: $this->updateTarget, entityType: $this->updateTarget, entityId: (int) $document->getId(), entityId: (int) $document->getId(), withPriority: true priority: QueuePriorityEnum::HIGH, ); ); } } app/Component/ES/Processor/DTOs/SelectionList.php +54-17Lines changed: 54 additions & 17 deletions Original file line numberOriginal file lineDiff line numberDiff line change namespace Jiminny\Component\ES\Processor\DTOs; namespace Jiminny\Component\ES\Processor\DTOs; use Jiminny\Component\ES\QueuePriorityEnum; /** /** * A very basic and simple collection of entity IDs. * A very basic and simple collection of entity IDs. */ */ class SelectionList class SelectionList { { public function __construct( private const int DEFAULT_CHUNK = 200; private readonly array $priorityEntityIdList = [], private readonly array $normalEntityIdList = [], private int $chunkSize = self::DEFAULT_CHUNK; private readonly bool $isStaleChunkSelected = false, private bool $isStaleChunkSelected = false; private readonly int $chunkSize = 200, private array $selectedEntityIds = []; ) { // Do nothing public function setChunkSize(int $chunkSize): void { $this->chunkSize = $chunkSize; } } public function getAllIds(): array public function markStale(): void { { return array_merge($this->priorityEntityIdList, $this->normalEntityIdList); $this->isStaleChunkSelected = true; } } public function count(): int public function addEntityList(string|QueuePriorityEnum $priority, array $entityIds): void { { return count($this->priorityEntityIdList) + count($this->normalEntityIdList); $priorityKey = $this->normalisePriority($priority); if (! array_key_exists($priorityKey, $this->selectedEntityIds)) { $this->selectedEntityIds[$priorityKey] = []; } $this->selectedEntityIds[$priorityKey] = array_merge($this->selectedEntityIds[$priorityKey], $entityIds); } } public function isEmpty(): bool /** * @return string[] */ public function getEntityListGroups(): array { { return empty($this->priorityEntityIdList) && empty($this->normalEntityIdList); return array_keys($this->selectedEntityIds); } } public function getHighPriorityEntityIds(): array public function getEntityListItemsByGroup(string|QueuePriorityEnum $priority): array { { return $this->priorityEntityIdList; $priorityKey = $this->normalisePriority($priority); return $this->selectedEntityIds[$priorityKey] ?? []; } } public function getNormalPriorityEntityId(): array public function getAllIds(): array { { return $this->normalEntityIdList; $allIds = []; foreach ($this->selectedEntityIds as $entityIds) { $allIds = array_merge($allIds, $entityIds); } return $allIds; } public function count(): int { return array_sum( array_map('count', $this->selectedEntityIds) ); } public function isEmpty(): bool { return $this->count() === 0; } } public function isStaleChunkSelected(): bool public function isStaleChunkSelected(): bool { { return $this->count() >= $this->chunkSize; return $this->count() >= $this->chunkSize; } } private function normalisePriority(string|QueuePriorityEnum $priority): string { return $priority instanceof QueuePriorityEnum ? $priority->value : $priority; } } } app/Component/ES/Processor/Traits/SelectEntityListTrait.php +27-4Lines changed: 27 additions & 4 deletions Original file line numberOriginal file lineDiff line numberDiff line change use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; /** /** * Build the correct source list name for the type of entity and priority * Build the correct source list name for the type of entity and priority */ */ trait SelectEntityListTrait trait SelectEntityListTrait { { /** * Highest priority queue for data requiring near-instant availability. * Very few entities should be added here, only when absolutely necessary. */ private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; /** * Normal priority queue for normal application operations. * Almost all update events should pass through this queue */ private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; protected static function selectTargetList(string $entityType, bool $withPriority = false): string /** { * Nonblocking low priority queue. This queue will be consumed only when there is nothing * with higher priority. * * This queue will be used for operations such as es:reset-async */ private const string ENTITIES_LOW_PRIORITIES_LIST = '%s-for-update-low'; protected static function selectTargetList( string $entityType, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { if (! in_array($entityType, UpdateTarget::allowedTargets())) { if (! in_array($entityType, UpdateTarget::allowedTargets())) { throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); } } if ($withPriority) { if ($priority->isHigh()) { Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); } } if ($priority->isLow()) { return sprintf(self::ENTITIES_LOW_PRIORITIES_LIST, $entityType); } return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); } } } } app/Component/ES/Processor/TargetEntitiesSelector.php +26-21Lines changed: 26 additions & 21 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SelectionList; use Jiminny\Component\ES\Processor\DTOs\SelectionList; use Jiminny\Component\ES\Processor\Traits\ExtractIdsTrait; use Jiminny\Component\ES\Processor\Traits\ExtractIdsTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\QueuePriorityEnum; /** /** * This class supplies a list of entities pending an update. * This class supplies a list of entities pending an update. public function select(): SelectionList public function select(): SelectionList { { $staleWorkEntityIds = $this->getStaleChunk(); $selectionList = new SelectionList(); $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $staleWorkEntityIds = $this->getStaleChunk(); if (count($staleWorkEntityIds) > 0) { if (count($staleWorkEntityIds) > 0) { return new SelectionList( /** priorityEntityIdList: $staleWorkEntityIds, * Stale chunks are treated as high priority isStaleChunkSelected: true, */ chunkSize: ChunkSize::getStaleChunkSize($this->updateTarget), $selectionList->markStale(); ); $selectionList->addEntityList(QueuePriorityEnum::HIGH, $staleWorkEntityIds); $selectionList->setChunkSize(ChunkSize::getStaleChunkSize($this->updateTarget)); return $selectionList; } } $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $selectionList->setChunkSize($mainChunkSize); $priorityEntityIdsList = $this->extractIdsFromSet( $priorityEntityIdsList = $this->extractIds(QueuePriorityEnum::HIGH, $mainChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, true), $selectionList->addEntityList(QueuePriorityEnum::HIGH, $priorityEntityIdsList); $mainChunkSize, ); $normalEntityIdsList = []; $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); if ($normalEntityChunkSize > 0) { if ($normalEntityChunkSize > 0) { $normalEntityIdsList = $this->extractIdsFromSet( $normalEntityIdsList = $this->extractIds(QueuePriorityEnum::NORMAL, $normalEntityChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, false), $selectionList->addEntityList(QueuePriorityEnum::NORMAL, $normalEntityIdsList); $normalEntityChunkSize ); } } return new SelectionList( return $selectionList; priorityEntityIdList: $priorityEntityIdsList, normalEntityIdList: $normalEntityIdsList, chunkSize: $mainChunkSize ); } } private function getStaleChunk(): array private function getStaleChunk(): array return []; return []; } } private function extractIds(QueuePriorityEnum $priority, int $chunkSize): array { return $this->extractIdsFromSet( AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, $priority), $chunkSize ); } } } app/Component/ES/AsyncUpdateElasticSearch.php +17-10Lines changed: 17 additions & 10 deletions Original file line numberOriginal file lineDiff line numberDiff line change * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * and other activity related data * and other activity related data */ */ public static function markEntityForUpdate(string $entityType, int $entityId, bool $withPriority = false): void public static function markEntityForUpdate( { string $entityType, $targetList = self::selectTargetList($entityType, $withPriority); int $entityId, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { $targetList = self::selectTargetList($entityType, $priority); Redis::sadd($targetList, $entityId); Redis::sadd($targetList, $entityId); Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ 'entityType' => $entityType, 'entityType' => $entityType, 'entityId' => $entityId, 'entityId' => $entityId, 'collectionKey' => $targetList, 'collectionKey' => $targetList, 'withPriority' => $withPriority, 'priority' => $priority->value, ]); ]); } } public static function bulkMarkEntitiesForUpdate( public static function bulkMarkEntitiesForUpdate( string $entityType, string $entityType, array $entityIds, array $entityIds, bool $withPriority = false QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { ): void { if (empty($entityIds)) { if (empty($entityIds)) { return; return; } } $targetList = self::selectTargetList($entityType, $withPriority); $targetList = self::selectTargetList($entityType, $priority); Redis::saddarray($targetList, $entityIds); Redis::saddarray($targetList, $entityIds); } } * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Takes priority into consideration. * Takes priority into consideration. */ */ public static function getEntitiesSourceList(string $updateTarget, $priority = false): string public static function getEntitiesSourceList( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { return self::selectTargetList($updateTarget, $priority); return self::selectTargetList($updateTarget, $priority); } } /** /** * Externally called helper methods * Externally called helper methods * - count and flush * - count and flush */ */ public static function getEntitiesListCount(string $updateTarget, $priority = false): int public static function getEntitiesListCount( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): int { $targetList = self::selectTargetList($updateTarget, $priority); $targetList = self::selectTargetList($updateTarget, $priority); return Redis::scard($targetList); return Redis::scard($targetList); app/Component/ES/QueuePriorityEnum.php +40Lines changed: 40 additions & 0 deletions Original file line numberOriginal file lineDiff line numberDiff line change <?php declare(strict_types=1); namespace Jiminny\Component\ES; use Jiminny\Exceptions\InvalidArgumentException; enum QueuePriorityEnum: string { case HIGH = 'high'; case NORMAL = 'normal'; case LOW = 'low'; public static function tryFromString(string $value): self { if (! self::isValid($value)) { throw new InvalidArgumentException( sprintf('Invalid queue priority "%s" selected', $value) ); } return self::tryFrom($value); } public static function isValid(string $value): bool { return self::tryFrom($value) !== null; } public function isLow(): bool { return $this === self::LOW; } public function isHigh(): bool { return $this === self::HIGH; } } app/Component/ES/UpdateProcessManager.php +12-9Lines changed: 12 additions & 9 deletions Original file line numberOriginal file lineDiff line numberDiff line change if ($selectionList->isEmpty()) { if ($selectionList->isEmpty()) { return false; return false; } } /** /** * A stale chunk will always be smaller than a regular chunk. * A stale chunk will always be smaller than a regular chunk. * That doesn't mean there aren't any other scheduled entities for processing * That doesn't mean there aren't any other scheduled entities for processing private function rescheduleThrottledEntities(SelectionList $selectionList): void private function rescheduleThrottledEntities(SelectionList $selectionList): void { { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $groups = $selectionList->getEntityListGroups(); $this->updateTarget, foreach ($groups as $eachGroup) { $selectionList->getNormalPriorityEntityId() $groupEntityIds = $selectionList->getEntityListItemsByGroup($eachGroup); ); if (! empty($groupEntityIds)) { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $this->updateTarget, entityType: $this->updateTarget, $selectionList->getHighPriorityEntityIds(), entityIds: $groupEntityIds, true priority: QueuePriorityEnum::tryFromString($eachGroup) ); ); } } } } } } app/Console/Commands/Elasticsearch/AsyncUpdateEsEntities.php +9-3Lines changed: 9 additions & 3 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Illuminate\Support\Str; use Illuminate\Support\Str; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Component\ES\UpdateProcessManager; use Jiminny\Component\ES\UpdateProcessManager; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Traits\GracefullyStoppable; use Jiminny\Traits\GracefullyStoppable; Redis::set($gaugeLockName, true); Redis::set($gaugeLockName, true); Redis::expire($gaugeLockName, 60); Redis::expire($gaugeLockName, 60); $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::HIGH), ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update', $updateTarget), stat: sprintf('jiminny.%s-for-update', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::NORMAL), ); ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), stat: sprintf('jiminny.%s-for-update-low', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, true), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::LOW), ); ); } } app/Console/Commands/Elasticsearch/ResetAsyncElasticSearchCommand.php +5-1Lines changed: 5 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\Traits\ValidateUpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\ValidateUpdateTargetTrait; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Component\ES\Repositories\EsResetRepositoryInterface; use Jiminny\Component\ES\Repositories\EsResetRepositoryInterface; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Traits\GracefullyStoppable; use Jiminny\Traits\GracefullyStoppable; private function getRemainingScheduledEntities(bool $printStatus = false): int private function getRemainingScheduledEntities(bool $printStatus = false): int { { $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget, true); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount( $this->updateTarget, QueuePriorityEnum::HIGH ); if ($printStatus) { if ($printStatus) { $this->line( $this->line(
You said
app/Component/ES/Listeners/UpdateMultipleTargetsListener.php
+2-1Lines changed: 2 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\Component\ES\Listeners;
namespace Jiminny\Component\ES\Listeners;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\QueuePriorityEnum;
use Jiminny\Contracts\ES\Events\UpdateMultipleEntities;
use Jiminny\Contracts\ES\Events\UpdateMultipleEntities;
use Psr\Log\LoggerInterface;
use Psr\Log\LoggerInterface;
AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(
AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(
$event->getUpdateTargetValue(),
$event->getUpdateTargetValue(),
$event->getEntities(),
$event->getEntities(),
$event->isPriority()
$event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL,
);
);
}
}
}
}
app/Component/ES/Listeners/UpdateSingleTargetListener.php
+9-1Lines changed: 9 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Actions\TrackElasticSearchOperations;
use Jiminny\Component\ES\Actions\TrackElasticSearchOperations;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\Processor\EntityQueryBuilder;
use Jiminny\Component\ES\Processor\EntityQueryBuilder;
use Jiminny\Component\ES\QueuePriorityEnum;
use Jiminny\Contracts\ES\Events\UpdateSingleEntity;
use Jiminny\Contracts\ES\Events\UpdateSingleEntity;
use Psr\Log\LoggerInterface;
use Psr\Log\LoggerInterface;
'entityId' => $event->getEntityId(),
'entityId' => $event->getEntityId(),
]);
]);
/**
* @important:
* Synchronous event should eventually be deprecated.
* Instant write operations are blocking and should be used sparingly.
* It is much better in terms of performance to write 100 or 1000 documents at once,
* and have one blocking reindex operation, instead of writing 10 documents synchronously.
*/
if ($event->isSyncEvent()) {
if ($event->isSyncEvent()) {
$this->handleSyncEvent($event);
$this->handleSyncEvent($event);
AsyncUpdateElasticSearch::markEntityForUpdate(
AsyncUpdateElasticSearch::markEntityForUpdate(
$event->getUpdateTargetValue(),
$event->getUpdateTargetValue(),
$event->getEntityId(),
$event->getEntityId(),
$event->isPriority()
$event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL,
);
);
}
}
app/Component/ES/Processor/Actions/UpsertDocumentsAction.php
+2-1Lines changed: 2 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SimpleCollection;
use Jiminny\Component\ES\Processor\DTOs\SimpleCollection;
use Jiminny\Component\ES\Processor\ResponseEvaluator;
use Jiminny\Component\ES\Processor\ResponseEvaluator;
use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait;
use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait;
use Jiminny\Component\ES\QueuePriorityEnum;
use Jiminny\Exceptions\InvalidDataException;
use Jiminny\Exceptions\InvalidDataException;
use Sentry\Laravel\Facade as Sentry;
use Sentry\Laravel\Facade as Sentry;
AsyncUpdateElasticSearch::markEntityForUpdate(
AsyncUpdateElasticSearch::markEntityForUpdate(
entityType: $this->updateTarget,
entityType: $this->updateTarget,
entityId: (int) $document->getId(),
entityId: (int) $document->getId(),
withPriority: true
priority: QueuePriorityEnum::HIGH,
);
);
}
}
app/Component/ES/Processor/DTOs/SelectionList.php
+54-17Lines changed: 54 additions & 17 deletions
Original file line numberOriginal file lineDiff line numberDiff line change
namespace Jiminny\Component\ES\Processor\DTOs;
namespace Jiminny\Component\ES\Processor\DTOs;
use Jiminny\Component\ES\QueuePriorityEnum;
/**
/**
* A very basic and simple collection of entity IDs.
* A very basic and simple collection of entity IDs.
*/
*/
class SelectionList
class SelectionList
{
{
public function __construct(
private const int DEFAULT_CHUNK = 200;
private readonly array $priorityEntityIdList = [],
private readonly array $normalEntityIdList = [],
private int $chunkSize = self::DEFAULT_CHUNK;
private readonly bool $isStaleChunkSelected = false,
private bool $isStaleChunkSelected = false;
private readonly int $chunkSize = 200,
private array $selectedEntityIds = [];
) {
// Do nothing
public function setChunkSize(int $chunkSize): void
{
$this->chunkSize = $chunkSize;
}
}...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
55695
|
NULL
|
0
|
2026-05-19T06:41:32.663057+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779172892663_m1.jpg...
|
Firefox
|
JY-20808 low priority indexing queue by Vasil-Jimi JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app — Work...
|
1
|
github.com/jiminny/app/pull/12082/changes#diff-e5d github.com/jiminny/app/pull/12082/changes#diff-e5dcbcff071d212d7289a3afae523499caf0603272c50b6da48a278910b9ca09...
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
Close tab
New Tab
Customize sidebar
Close Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
AI Chat settings
Close
WORK, Google Account: [EMAIL]
Main menu
New chat
Gemini
New Chat
Open menu for conversation actions.
Conversation with Gemini
Conversation with Gemini
Show the uploaded image in a lightbox
Copy prompt
You said Make a PR of changes Find potential issues and bottlenecks
You said
Make a PR of changes Find potential issues and bottlenecks
Listen
Show thinking
Gemini said
Gemini said
I can see you've uploaded a screenshot of a code diff, likely from a version control system given the red and green highlights. I would love to help you review the changes, spot bottlenecks, and help you draft a Pull Request.
However,
the image resolution is far too low for me to read.
It appears to be a completely zoomed-out view where the code has been reduced to tiny, illegible pixels. Because of this, I cannot extract any text or logic to analyze.
How You Can Share the Code
How You Can Share the Code
To help me review your code effectively, please try one of the following:
Paste the text directly:
Copy the specific code blocks (both the old and new versions if possible) and paste them directly into our chat.
Upload the files:
If the changes are extensive, you can upload the raw text or code files.
Take high-resolution screenshots:
If you must use images, take closer, readable screenshots of the specific functions or methods you want me to review.
Once you provide the readable code, I can dive right in to identify potential bugs, assess performance bottlenecks, and help you summarize the changes for your PR!
Good response
Bad response
Share & export
Copy
Show more options
Copy prompt
Edit
You said app/Component/ES/Listeners/UpdateMultipleTargetsListener.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\Component\ES\Listeners; namespace Jiminny\Component\ES\Listeners; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Contracts\ES\Events\UpdateMultipleEntities; use Jiminny\Contracts\ES\Events\UpdateMultipleEntities; use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface; AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntities(), $event->getEntities(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } } } app/Component/ES/Listeners/UpdateSingleTargetListener.php +9-1Lines changed: 9 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Actions\TrackElasticSearchOperations; use Jiminny\Component\ES\Actions\TrackElasticSearchOperations; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Contracts\ES\Events\UpdateSingleEntity; use Jiminny\Contracts\ES\Events\UpdateSingleEntity; use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface; 'entityId' => $event->getEntityId(), 'entityId' => $event->getEntityId(), ]); ]); /** * @important: * Synchronous event should eventually be deprecated. * Instant write operations are blocking and should be used sparingly. * It is much better in terms of performance to write 100 or 1000 documents at once, * and have one blocking reindex operation, instead of writing 10 documents synchronously. */ if ($event->isSyncEvent()) { if ($event->isSyncEvent()) { $this->handleSyncEvent($event); $this->handleSyncEvent($event); AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntityId(), $event->getEntityId(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } app/Component/ES/Processor/Actions/UpsertDocumentsAction.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SimpleCollection; use Jiminny\Component\ES\Processor\DTOs\SimpleCollection; use Jiminny\Component\ES\Processor\ResponseEvaluator; use Jiminny\Component\ES\Processor\ResponseEvaluator; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Exceptions\InvalidDataException; use Jiminny\Exceptions\InvalidDataException; use Sentry\Laravel\Facade as Sentry; use Sentry\Laravel\Facade as Sentry; AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( entityType: $this->updateTarget, entityType: $this->updateTarget, entityId: (int) $document->getId(), entityId: (int) $document->getId(), withPriority: true priority: QueuePriorityEnum::HIGH, ); ); } } app/Component/ES/Processor/DTOs/SelectionList.php +54-17Lines changed: 54 additions & 17 deletions Original file line numberOriginal file lineDiff line numberDiff line change namespace Jiminny\Component\ES\Processor\DTOs; namespace Jiminny\Component\ES\Processor\DTOs; use Jiminny\Component\ES\QueuePriorityEnum; /** /** * A very basic and simple collection of entity IDs. * A very basic and simple collection of entity IDs. */ */ class SelectionList class SelectionList { { public function __construct( private const int DEFAULT_CHUNK = 200; private readonly array $priorityEntityIdList = [], private readonly array $normalEntityIdList = [], private int $chunkSize = self::DEFAULT_CHUNK; private readonly bool $isStaleChunkSelected = false, private bool $isStaleChunkSelected = false; private readonly int $chunkSize = 200, private array $selectedEntityIds = []; ) { // Do nothing public function setChunkSize(int $chunkSize): void { $this->chunkSize = $chunkSize; } } public function getAllIds(): array public function markStale(): void { { return array_merge($this->priorityEntityIdList, $this->normalEntityIdList); $this->isStaleChunkSelected = true; } } public function count(): int public function addEntityList(string|QueuePriorityEnum $priority, array $entityIds): void { { return count($this->priorityEntityIdList) + count($this->normalEntityIdList); $priorityKey = $this->normalisePriority($priority); if (! array_key_exists($priorityKey, $this->selectedEntityIds)) { $this->selectedEntityIds[$priorityKey] = []; } $this->selectedEntityIds[$priorityKey] = array_merge($this->selectedEntityIds[$priorityKey], $entityIds); } } public function isEmpty(): bool /** * @return string[] */ public function getEntityListGroups(): array { { return empty($this->priorityEntityIdList) && empty($this->normalEntityIdList); return array_keys($this->selectedEntityIds); } } public function getHighPriorityEntityIds(): array public function getEntityListItemsByGroup(string|QueuePriorityEnum $priority): array { { return $this->priorityEntityIdList; $priorityKey = $this->normalisePriority($priority); return $this->selectedEntityIds[$priorityKey] ?? []; } } public function getNormalPriorityEntityId(): array public function getAllIds(): array { { return $this->normalEntityIdList; $allIds = []; foreach ($this->selectedEntityIds as $entityIds) { $allIds = array_merge($allIds, $entityIds); } return $allIds; } public function count(): int { return array_sum( array_map('count', $this->selectedEntityIds) ); } public function isEmpty(): bool { return $this->count() === 0; } } public function isStaleChunkSelected(): bool public function isStaleChunkSelected(): bool { { return $this->count() >= $this->chunkSize; return $this->count() >= $this->chunkSize; } } private function normalisePriority(string|QueuePriorityEnum $priority): string { return $priority instanceof QueuePriorityEnum ? $priority->value : $priority; } } } app/Component/ES/Processor/Traits/SelectEntityListTrait.php +27-4Lines changed: 27 additions & 4 deletions Original file line numberOriginal file lineDiff line numberDiff line change use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; /** /** * Build the correct source list name for the type of entity and priority * Build the correct source list name for the type of entity and priority */ */ trait SelectEntityListTrait trait SelectEntityListTrait { { /** * Highest priority queue for data requiring near-instant availability. * Very few entities should be added here, only when absolutely necessary. */ private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; /** * Normal priority queue for normal application operations. * Almost all update events should pass through this queue */ private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; protected static function selectTargetList(string $entityType, bool $withPriority = false): string /** { * Nonblocking low priority queue. This queue will be consumed only when there is nothing * with higher priority. * * This queue will be used for operations such as es:reset-async */ private const string ENTITIES_LOW_PRIORITIES_LIST = '%s-for-update-low'; protected static function selectTargetList( string $entityType, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { if (! in_array($entityType, UpdateTarget::allowedTargets())) { if (! in_array($entityType, UpdateTarget::allowedTargets())) { throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); } } if ($withPriority) { if ($priority->isHigh()) { Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); } } if ($priority->isLow()) { return sprintf(self::ENTITIES_LOW_PRIORITIES_LIST, $entityType); } return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); } } } } app/Component/ES/Processor/TargetEntitiesSelector.php +26-21Lines changed: 26 additions & 21 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SelectionList; use Jiminny\Component\ES\Processor\DTOs\SelectionList; use Jiminny\Component\ES\Processor\Traits\ExtractIdsTrait; use Jiminny\Component\ES\Processor\Traits\ExtractIdsTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\QueuePriorityEnum; /** /** * This class supplies a list of entities pending an update. * This class supplies a list of entities pending an update. public function select(): SelectionList public function select(): SelectionList { { $staleWorkEntityIds = $this->getStaleChunk(); $selectionList = new SelectionList(); $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $staleWorkEntityIds = $this->getStaleChunk(); if (count($staleWorkEntityIds) > 0) { if (count($staleWorkEntityIds) > 0) { return new SelectionList( /** priorityEntityIdList: $staleWorkEntityIds, * Stale chunks are treated as high priority isStaleChunkSelected: true, */ chunkSize: ChunkSize::getStaleChunkSize($this->updateTarget), $selectionList->markStale(); ); $selectionList->addEntityList(QueuePriorityEnum::HIGH, $staleWorkEntityIds); $selectionList->setChunkSize(ChunkSize::getStaleChunkSize($this->updateTarget)); return $selectionList; } } $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $selectionList->setChunkSize($mainChunkSize); $priorityEntityIdsList = $this->extractIdsFromSet( $priorityEntityIdsList = $this->extractIds(QueuePriorityEnum::HIGH, $mainChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, true), $selectionList->addEntityList(QueuePriorityEnum::HIGH, $priorityEntityIdsList); $mainChunkSize, ); $normalEntityIdsList = []; $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); if ($normalEntityChunkSize > 0) { if ($normalEntityChunkSize > 0) { $normalEntityIdsList = $this->extractIdsFromSet( $normalEntityIdsList = $this->extractIds(QueuePriorityEnum::NORMAL, $normalEntityChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, false), $selectionList->addEntityList(QueuePriorityEnum::NORMAL, $normalEntityIdsList); $normalEntityChunkSize ); } } return new SelectionList( return $selectionList; priorityEntityIdList: $priorityEntityIdsList, normalEntityIdList: $normalEntityIdsList, chunkSize: $mainChunkSize ); } } private function getStaleChunk(): array private function getStaleChunk(): array return []; return []; } } private function extractIds(QueuePriorityEnum $priority, int $chunkSize): array { return $this->extractIdsFromSet( AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, $priority), $chunkSize ); } } } app/Component/ES/AsyncUpdateElasticSearch.php +17-10Lines changed: 17 additions & 10 deletions Original file line numberOriginal file lineDiff line numberDiff line change * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * and other activity related data * and other activity related data */ */ public static function markEntityForUpdate(string $entityType, int $entityId, bool $withPriority = false): void public static function markEntityForUpdate( { string $entityType, $targetList = self::selectTargetList($entityType, $withPriority); int $entityId, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { $targetList = self::selectTargetList($entityType, $priority); Redis::sadd($targetList, $entityId); Redis::sadd($targetList, $entityId); Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ 'entityType' => $entityType, 'entityType' => $entityType, 'entityId' => $entityId, 'entityId' => $entityId, 'collectionKey' => $targetList, 'collectionKey' => $targetList, 'withPriority' => $withPriority, 'priority' => $priority->value, ]); ]); } } public static function bulkMarkEntitiesForUpdate( public static function bulkMarkEntitiesForUpdate( string $entityType, string $entityType, array $entityIds, array $entityIds, bool $withPriority = false QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { ): void { if (empty($entityIds)) { if (empty($entityIds)) { return; return; } } $targetList = self::selectTargetList($entityType, $withPriority); $targetList = self::selectTargetList($entityType, $priority); Redis::saddarray($targetList, $entityIds); Redis::saddarray($targetList, $entityIds); } } * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Takes priority into consideration. * Takes priority into consideration. */ */ public static function getEntitiesSourceList(string $updateTarget, $priority = false): string public static function getEntitiesSourceList( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { return self::selectTargetList($updateTarget, $priority); return self::selectTargetList($updateTarget, $priority); } } /** /** * Externally called helper methods * Externally called helper methods * - count and flush * - count and flush */ */ public static function getEntitiesListCount(string $updateTarget, $priority = false): int public static function getEntitiesListCount( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): int { $targetList = self::selectTargetList($updateTarget, $priority); $targetList = self::selectTargetList($updateTarget, $priority); return Redis::scard($targetList); return Redis::scard($targetList); app/Component/ES/QueuePriorityEnum.php +40Lines changed: 40 additions & 0 deletions Original file line numberOriginal file lineDiff line numberDiff line change <?php declare(strict_types=1); namespace Jiminny\Component\ES; use Jiminny\Exceptions\InvalidArgumentException; enum QueuePriorityEnum: string { case HIGH = 'high'; case NORMAL = 'normal'; case LOW = 'low'; public static function tryFromString(string $value): self { if (! self::isValid($value)) { throw new InvalidArgumentException( sprintf('Invalid queue priority "%s" selected', $value) ); } return self::tryFrom($value); } public static function isValid(string $value): bool { return self::tryFrom($value) !== null; } public function isLow(): bool { return $this === self::LOW; } public function isHigh(): bool { return $this === self::HIGH; } } app/Component/ES/UpdateProcessManager.php +12-9Lines changed: 12 additions & 9 deletions Original file line numberOriginal file lineDiff line numberDiff line change if ($selectionList->isEmpty()) { if ($selectionList->isEmpty()) { return false; return false; } } /** /** * A stale chunk will always be smaller than a regular chunk. * A stale chunk will always be smaller than a regular chunk. * That doesn't mean there aren't any other scheduled entities for processing * That doesn't mean there aren't any other scheduled entities for processing private function rescheduleThrottledEntities(SelectionList $selectionList): void private function rescheduleThrottledEntities(SelectionList $selectionList): void { { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $groups = $selectionList->getEntityListGroups(); $this->updateTarget, foreach ($groups as $eachGroup) { $selectionList->getNormalPriorityEntityId() $groupEntityIds = $selectionList->getEntityListItemsByGroup($eachGroup); ); if (! empty($groupEntityIds)) { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $this->updateTarget, entityType: $this->updateTarget, $selectionList->getHighPriorityEntityIds(), entityIds: $groupEntityIds, true priority: QueuePriorityEnum::tryFromString($eachGroup) ); ); } } } } } } app/Console/Commands/Elasticsearch/AsyncUpdateEsEntities.php +9-3Lines changed: 9 additions & 3 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Illuminate\Support\Str; use Illuminate\Support\Str; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Component\ES\UpdateProcessManager; use Jiminny\Component\ES\UpdateProcessManager; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Traits\GracefullyStoppable; use Jiminny\Traits\GracefullyStoppable; Redis::set($gaugeLockName, true); Redis::set($gaugeLockName, true); Redis::expire($gaugeLockName, 60); Redis::expire($gaugeLockName, 60); $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::HIGH), ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update', $updateTarget), stat: sprintf('jiminny.%s-for-update', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::NORMAL), ); ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), stat: sprintf('jiminny.%s-for-update-low', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, true), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::LOW), ); ); } } app/Console/Commands/Elasticsearch/ResetAsyncElasticSearchCommand.php +5-1Lines changed: 5 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\Traits\ValidateUpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\ValidateUpdateTargetTrait; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Component\ES\Repositories\EsResetRepositoryInterface; use Jiminny\Component\ES\Repositories\EsResetRepositoryInterface; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Traits\GracefullyStoppable; use Jiminny\Traits\GracefullyStoppable; private function getRemainingScheduledEntities(bool $printStatus = false): int private function getRemainingScheduledEntities(bool $printStatus = false): int { { $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget, true); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount( $this->updateTarget, QueuePriorityEnum::HIGH ); if ($printStatus) { if ($printStatus) { $this->line( $this->line(
You said
app/Component/ES/Listeners/UpdateMultipleTargetsListener.php
+2-1Lines changed: 2 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\Component\ES\Listeners;
namespace Jiminny\Component\ES\Listeners;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\QueuePriorityEnum;
use Jiminny\Contracts\ES\Events\UpdateMultipleEntities;
use Jiminny\Contracts\ES\Events\UpdateMultipleEntities;
use Psr\Log\LoggerInterface;
use Psr\Log\LoggerInterface;
AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(
AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(
$event->getUpdateTargetValue(),
$event->getUpdateTargetValue(),
$event->getEntities(),
$event->getEntities(),
$event->isPriority()
$event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL,
);
);
}
}
}
}
app/Component/ES/Listeners/UpdateSingleTargetListener.php
+9-1Lines changed: 9 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Actions\TrackElasticSearchOperations;
use Jiminny\Component\ES\Actions\TrackElasticSearchOperations;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\Processor\EntityQueryBuilder;
use Jiminny\Component\ES\Processor\EntityQueryBuilder;
use Jiminny\Component\ES\QueuePriorityEnum;
use Jiminny\Contracts\ES\Events\UpdateSingleEntity;
use Jiminny\Contracts\ES\Events\UpdateSingleEntity;
use Psr\Log\LoggerInterface;
use Psr\Log\LoggerInterface;
'entityId' => $event->getEntityId(),
'entityId' => $event->getEntityId(),
]);
]);
/**
* @important:
* Synchronous event should eventually be deprecated.
* Instant write operations are blocking and should be used sparingly.
* It is much better in terms of performance to write 100 or 1000 documents at once,
* and have one blocking reindex operation, instead of writing 10 documents synchronously.
*/
if ($event->isSyncEvent()) {
if ($event->isSyncEvent()) {
$this->handleSyncEvent($event);
$this->handleSyncEvent($event);
AsyncUpdateElasticSearch::markEntityForUpdate(
AsyncUpdateElasticSearch::markEntityForUpdate(
$event->getUpdateTargetValue(),
$event->getUpdateTargetValue(),
$event->getEntityId(),
$event->getEntityId(),
$event->isPriority()
$event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL,
);
);
}
}
app/Component/ES/Processor/Actions/UpsertDocumentsAction.php
+2-1Lines changed: 2 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SimpleCollection;
use Jiminny\Component\ES\Processor\DTOs\SimpleCollection;
use Jiminny\Component\ES\Processor\ResponseEvaluator;
use Jiminny\Component\ES\Processor\ResponseEvaluator;
use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait;
use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait;
use Jiminny\Component\ES\QueuePriorityEnum;
use Jiminny\Exceptions\InvalidDataException;
use Jiminny\Exceptions\InvalidDataException;
use Sentry\Laravel\Facade as Sentry;
use Sentry\Laravel\Facade as Sentry;
AsyncUpdateElasticSearch::markEntityForUpdate(
AsyncUpdateElasticSearch::markEntityForUpdate(
entityType: $this->updateTarget,
entityType: $this->updateTarget,
entityId: (int) $document->getId(),
entityId: (int) $document->getId(),
withPriority: true
priority: QueuePriorityEnum::HIGH,
);
);
}
}
app/Component/ES/Processor/DTOs/SelectionList.php
+54-17Lines changed: 54 additions & 17 deletions
Original file line numberOriginal file lineDiff line numberDiff line change
namespace Jiminny\Component\ES\Processor\DTOs;
namespace Jiminny\Component\ES\Processor\DTOs;
use Jiminny\Component\ES\QueuePriorityEnum;
/**
/**
* A very basic and simple collection of entity IDs.
* A very basic and simple collection of entity IDs.
*/
*/
class SelectionList
class SelectionList
{
{
public function __construct(
private const int DEFAULT_CHUNK = 200;
private readonly array $priorityEntityIdList = [],
private readonly array $normalEntityIdList = [],
private int $chunkSize = self::DEFAULT_CHUNK;
private readonly bool $isStaleChunkSelected = false,
private bool $isStaleChunkSelected = false;
private readonly int $chunkSize = 200,
private array $selectedEntityIds = [];
) {
// Do nothing
public function setChunkSize(int $chunkSize): void
{
$this->chunkSize = $chunkSize;
}
}
public function getAllIds(): array
public function markStale(): void
{
{
return array_merge($this->priorityEntityIdList, $this->normalEntityIdList);
$this->isStaleChunkSelected = true;
}...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New Tab","depth":4,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Close Google Gemini (⌃X)","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Tabs from other devices","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"AI Chat settings","depth":7,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Close","depth":7,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"WORK, Google Account: lukas.kovalik@jiminny.com","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Main menu","depth":12,"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New chat","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Gemini","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"New Chat","depth":12,"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Open menu for conversation actions.","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXHeading","text":"Conversation with Gemini","depth":15,"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Conversation with Gemini","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Show the uploaded image in a lightbox","depth":21,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy prompt","depth":21,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"You said Make a PR of changes Find potential issues and bottlenecks","depth":21,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"You said","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Make a PR of changes Find potential issues and bottlenecks","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Listen","depth":22,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Show thinking","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Gemini said","depth":20,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Gemini said","depth":21,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"I can see you've uploaded a screenshot of a code diff, likely from a version control system given the red and green highlights. I would love to help you review the changes, spot bottlenecks, and help you draft a Pull Request.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"However,","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"the image resolution is far too low for me to read.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"It appears to be a completely zoomed-out view where the code has been reduced to tiny, illegible pixels. Because of this, I cannot extract any text or logic to analyze.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"How You Can Share the Code","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"How You Can Share the Code","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"To help me review your code effectively, please try one of the following:","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Paste the text directly:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Copy the specific code blocks (both the old and new versions if possible) and paste them directly into our chat.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Upload the files:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"If the changes are extensive, you can upload the raw text or code files.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Take high-resolution screenshots:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"If you must use images, take closer, readable screenshots of the specific functions or methods you want me to review.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Once you provide the readable code, I can dive right in to identify potential bugs, assess performance bottlenecks, and help you summarize the changes for your PR!","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Good response","depth":22,"on_screen":false,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Bad response","depth":22,"on_screen":false,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Share & export","depth":21,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy","depth":22,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Show more options","depth":21,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy prompt","depth":21,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Edit","depth":21,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"You said app/Component/ES/Listeners/UpdateMultipleTargetsListener.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\\Component\\ES\\Listeners; namespace Jiminny\\Component\\ES\\Listeners; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Contracts\\ES\\Events\\UpdateMultipleEntities; use Jiminny\\Contracts\\ES\\Events\\UpdateMultipleEntities; use Psr\\Log\\LoggerInterface; use Psr\\Log\\LoggerInterface; AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntities(), $event->getEntities(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } } } app/Component/ES/Listeners/UpdateSingleTargetListener.php +9-1Lines changed: 9 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Actions\\TrackElasticSearchOperations; use Jiminny\\Component\\ES\\Actions\\TrackElasticSearchOperations; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder; use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Contracts\\ES\\Events\\UpdateSingleEntity; use Jiminny\\Contracts\\ES\\Events\\UpdateSingleEntity; use Psr\\Log\\LoggerInterface; use Psr\\Log\\LoggerInterface; 'entityId' => $event->getEntityId(), 'entityId' => $event->getEntityId(), ]); ]); /** * @important: * Synchronous event should eventually be deprecated. * Instant write operations are blocking and should be used sparingly. * It is much better in terms of performance to write 100 or 1000 documents at once, * and have one blocking reindex operation, instead of writing 10 documents synchronously. */ if ($event->isSyncEvent()) { if ($event->isSyncEvent()) { $this->handleSyncEvent($event); $this->handleSyncEvent($event); AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntityId(), $event->getEntityId(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } app/Component/ES/Processor/Actions/UpsertDocumentsAction.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Processor\\DTOs\\SimpleCollection; use Jiminny\\Component\\ES\\Processor\\DTOs\\SimpleCollection; use Jiminny\\Component\\ES\\Processor\\ResponseEvaluator; use Jiminny\\Component\\ES\\Processor\\ResponseEvaluator; use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait; use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Exceptions\\InvalidDataException; use Jiminny\\Exceptions\\InvalidDataException; use Sentry\\Laravel\\Facade as Sentry; use Sentry\\Laravel\\Facade as Sentry; AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( entityType: $this->updateTarget, entityType: $this->updateTarget, entityId: (int) $document->getId(), entityId: (int) $document->getId(), withPriority: true priority: QueuePriorityEnum::HIGH, ); ); } } app/Component/ES/Processor/DTOs/SelectionList.php +54-17Lines changed: 54 additions & 17 deletions Original file line numberOriginal file lineDiff line numberDiff line change namespace Jiminny\\Component\\ES\\Processor\\DTOs; namespace Jiminny\\Component\\ES\\Processor\\DTOs; use Jiminny\\Component\\ES\\QueuePriorityEnum; /** /** * A very basic and simple collection of entity IDs. * A very basic and simple collection of entity IDs. */ */ class SelectionList class SelectionList { { public function __construct( private const int DEFAULT_CHUNK = 200; private readonly array $priorityEntityIdList = [], private readonly array $normalEntityIdList = [], private int $chunkSize = self::DEFAULT_CHUNK; private readonly bool $isStaleChunkSelected = false, private bool $isStaleChunkSelected = false; private readonly int $chunkSize = 200, private array $selectedEntityIds = []; ) { // Do nothing public function setChunkSize(int $chunkSize): void { $this->chunkSize = $chunkSize; } } public function getAllIds(): array public function markStale(): void { { return array_merge($this->priorityEntityIdList, $this->normalEntityIdList); $this->isStaleChunkSelected = true; } } public function count(): int public function addEntityList(string|QueuePriorityEnum $priority, array $entityIds): void { { return count($this->priorityEntityIdList) + count($this->normalEntityIdList); $priorityKey = $this->normalisePriority($priority); if (! array_key_exists($priorityKey, $this->selectedEntityIds)) { $this->selectedEntityIds[$priorityKey] = []; } $this->selectedEntityIds[$priorityKey] = array_merge($this->selectedEntityIds[$priorityKey], $entityIds); } } public function isEmpty(): bool /** * @return string[] */ public function getEntityListGroups(): array { { return empty($this->priorityEntityIdList) && empty($this->normalEntityIdList); return array_keys($this->selectedEntityIds); } } public function getHighPriorityEntityIds(): array public function getEntityListItemsByGroup(string|QueuePriorityEnum $priority): array { { return $this->priorityEntityIdList; $priorityKey = $this->normalisePriority($priority); return $this->selectedEntityIds[$priorityKey] ?? []; } } public function getNormalPriorityEntityId(): array public function getAllIds(): array { { return $this->normalEntityIdList; $allIds = []; foreach ($this->selectedEntityIds as $entityIds) { $allIds = array_merge($allIds, $entityIds); } return $allIds; } public function count(): int { return array_sum( array_map('count', $this->selectedEntityIds) ); } public function isEmpty(): bool { return $this->count() === 0; } } public function isStaleChunkSelected(): bool public function isStaleChunkSelected(): bool { { return $this->count() >= $this->chunkSize; return $this->count() >= $this->chunkSize; } } private function normalisePriority(string|QueuePriorityEnum $priority): string { return $priority instanceof QueuePriorityEnum ? $priority->value : $priority; } } } app/Component/ES/Processor/Traits/SelectEntityListTrait.php +27-4Lines changed: 27 additions & 4 deletions Original file line numberOriginal file lineDiff line numberDiff line change use Illuminate\\Support\\Facades\\Log; use Illuminate\\Support\\Facades\\Log; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Exceptions\\InvalidArgumentException; use Jiminny\\Exceptions\\InvalidArgumentException; /** /** * Build the correct source list name for the type of entity and priority * Build the correct source list name for the type of entity and priority */ */ trait SelectEntityListTrait trait SelectEntityListTrait { { /** * Highest priority queue for data requiring near-instant availability. * Very few entities should be added here, only when absolutely necessary. */ private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; /** * Normal priority queue for normal application operations. * Almost all update events should pass through this queue */ private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; protected static function selectTargetList(string $entityType, bool $withPriority = false): string /** { * Nonblocking low priority queue. This queue will be consumed only when there is nothing * with higher priority. * * This queue will be used for operations such as es:reset-async */ private const string ENTITIES_LOW_PRIORITIES_LIST = '%s-for-update-low'; protected static function selectTargetList( string $entityType, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { if (! in_array($entityType, UpdateTarget::allowedTargets())) { if (! in_array($entityType, UpdateTarget::allowedTargets())) { throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); } } if ($withPriority) { if ($priority->isHigh()) { Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); } } if ($priority->isLow()) { return sprintf(self::ENTITIES_LOW_PRIORITIES_LIST, $entityType); } return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); } } } } app/Component/ES/Processor/TargetEntitiesSelector.php +26-21Lines changed: 26 additions & 21 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Processor\\DTOs\\SelectionList; use Jiminny\\Component\\ES\\Processor\\DTOs\\SelectionList; use Jiminny\\Component\\ES\\Processor\\Traits\\ExtractIdsTrait; use Jiminny\\Component\\ES\\Processor\\Traits\\ExtractIdsTrait; use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait; use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait; use Jiminny\\Component\\ES\\QueuePriorityEnum; /** /** * This class supplies a list of entities pending an update. * This class supplies a list of entities pending an update. public function select(): SelectionList public function select(): SelectionList { { $staleWorkEntityIds = $this->getStaleChunk(); $selectionList = new SelectionList(); $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $staleWorkEntityIds = $this->getStaleChunk(); if (count($staleWorkEntityIds) > 0) { if (count($staleWorkEntityIds) > 0) { return new SelectionList( /** priorityEntityIdList: $staleWorkEntityIds, * Stale chunks are treated as high priority isStaleChunkSelected: true, */ chunkSize: ChunkSize::getStaleChunkSize($this->updateTarget), $selectionList->markStale(); ); $selectionList->addEntityList(QueuePriorityEnum::HIGH, $staleWorkEntityIds); $selectionList->setChunkSize(ChunkSize::getStaleChunkSize($this->updateTarget)); return $selectionList; } } $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $selectionList->setChunkSize($mainChunkSize); $priorityEntityIdsList = $this->extractIdsFromSet( $priorityEntityIdsList = $this->extractIds(QueuePriorityEnum::HIGH, $mainChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, true), $selectionList->addEntityList(QueuePriorityEnum::HIGH, $priorityEntityIdsList); $mainChunkSize, ); $normalEntityIdsList = []; $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); if ($normalEntityChunkSize > 0) { if ($normalEntityChunkSize > 0) { $normalEntityIdsList = $this->extractIdsFromSet( $normalEntityIdsList = $this->extractIds(QueuePriorityEnum::NORMAL, $normalEntityChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, false), $selectionList->addEntityList(QueuePriorityEnum::NORMAL, $normalEntityIdsList); $normalEntityChunkSize ); } } return new SelectionList( return $selectionList; priorityEntityIdList: $priorityEntityIdsList, normalEntityIdList: $normalEntityIdsList, chunkSize: $mainChunkSize ); } } private function getStaleChunk(): array private function getStaleChunk(): array return []; return []; } } private function extractIds(QueuePriorityEnum $priority, int $chunkSize): array { return $this->extractIdsFromSet( AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, $priority), $chunkSize ); } } } app/Component/ES/AsyncUpdateElasticSearch.php +17-10Lines changed: 17 additions & 10 deletions Original file line numberOriginal file lineDiff line numberDiff line change * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * and other activity related data * and other activity related data */ */ public static function markEntityForUpdate(string $entityType, int $entityId, bool $withPriority = false): void public static function markEntityForUpdate( { string $entityType, $targetList = self::selectTargetList($entityType, $withPriority); int $entityId, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { $targetList = self::selectTargetList($entityType, $priority); Redis::sadd($targetList, $entityId); Redis::sadd($targetList, $entityId); Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ 'entityType' => $entityType, 'entityType' => $entityType, 'entityId' => $entityId, 'entityId' => $entityId, 'collectionKey' => $targetList, 'collectionKey' => $targetList, 'withPriority' => $withPriority, 'priority' => $priority->value, ]); ]); } } public static function bulkMarkEntitiesForUpdate( public static function bulkMarkEntitiesForUpdate( string $entityType, string $entityType, array $entityIds, array $entityIds, bool $withPriority = false QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { ): void { if (empty($entityIds)) { if (empty($entityIds)) { return; return; } } $targetList = self::selectTargetList($entityType, $withPriority); $targetList = self::selectTargetList($entityType, $priority); Redis::saddarray($targetList, $entityIds); Redis::saddarray($targetList, $entityIds); } } * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Takes priority into consideration. * Takes priority into consideration. */ */ public static function getEntitiesSourceList(string $updateTarget, $priority = false): string public static function getEntitiesSourceList( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { return self::selectTargetList($updateTarget, $priority); return self::selectTargetList($updateTarget, $priority); } } /** /** * Externally called helper methods * Externally called helper methods * - count and flush * - count and flush */ */ public static function getEntitiesListCount(string $updateTarget, $priority = false): int public static function getEntitiesListCount( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): int { $targetList = self::selectTargetList($updateTarget, $priority); $targetList = self::selectTargetList($updateTarget, $priority); return Redis::scard($targetList); return Redis::scard($targetList); app/Component/ES/QueuePriorityEnum.php +40Lines changed: 40 additions & 0 deletions Original file line numberOriginal file lineDiff line numberDiff line change <?php declare(strict_types=1); namespace Jiminny\\Component\\ES; use Jiminny\\Exceptions\\InvalidArgumentException; enum QueuePriorityEnum: string { case HIGH = 'high'; case NORMAL = 'normal'; case LOW = 'low'; public static function tryFromString(string $value): self { if (! self::isValid($value)) { throw new InvalidArgumentException( sprintf('Invalid queue priority \"%s\" selected', $value) ); } return self::tryFrom($value); } public static function isValid(string $value): bool { return self::tryFrom($value) !== null; } public function isLow(): bool { return $this === self::LOW; } public function isHigh(): bool { return $this === self::HIGH; } } app/Component/ES/UpdateProcessManager.php +12-9Lines changed: 12 additions & 9 deletions Original file line numberOriginal file lineDiff line numberDiff line change if ($selectionList->isEmpty()) { if ($selectionList->isEmpty()) { return false; return false; } } /** /** * A stale chunk will always be smaller than a regular chunk. * A stale chunk will always be smaller than a regular chunk. * That doesn't mean there aren't any other scheduled entities for processing * That doesn't mean there aren't any other scheduled entities for processing private function rescheduleThrottledEntities(SelectionList $selectionList): void private function rescheduleThrottledEntities(SelectionList $selectionList): void { { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $groups = $selectionList->getEntityListGroups(); $this->updateTarget, foreach ($groups as $eachGroup) { $selectionList->getNormalPriorityEntityId() $groupEntityIds = $selectionList->getEntityListItemsByGroup($eachGroup); ); if (! empty($groupEntityIds)) { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $this->updateTarget, entityType: $this->updateTarget, $selectionList->getHighPriorityEntityIds(), entityIds: $groupEntityIds, true priority: QueuePriorityEnum::tryFromString($eachGroup) ); ); } } } } } } app/Console/Commands/Elasticsearch/AsyncUpdateEsEntities.php +9-3Lines changed: 9 additions & 3 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Illuminate\\Support\\Str; use Illuminate\\Support\\Str; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Component\\ES\\UpdateProcessManager; use Jiminny\\Component\\ES\\UpdateProcessManager; use Jiminny\\Exceptions\\InvalidArgumentException; use Jiminny\\Exceptions\\InvalidArgumentException; use Jiminny\\Traits\\GracefullyStoppable; use Jiminny\\Traits\\GracefullyStoppable; Redis::set($gaugeLockName, true); Redis::set($gaugeLockName, true); Redis::expire($gaugeLockName, 60); Redis::expire($gaugeLockName, 60); $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::HIGH), ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update', $updateTarget), stat: sprintf('jiminny.%s-for-update', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::NORMAL), ); ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), stat: sprintf('jiminny.%s-for-update-low', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, true), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::LOW), ); ); } } app/Console/Commands/Elasticsearch/ResetAsyncElasticSearchCommand.php +5-1Lines changed: 5 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder; use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder; use Jiminny\\Component\\ES\\Processor\\Traits\\ValidateUpdateTargetTrait; use Jiminny\\Component\\ES\\Processor\\Traits\\ValidateUpdateTargetTrait; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Component\\ES\\Repositories\\EsResetRepositoryInterface; use Jiminny\\Component\\ES\\Repositories\\EsResetRepositoryInterface; use Jiminny\\Exceptions\\InvalidArgumentException; use Jiminny\\Exceptions\\InvalidArgumentException; use Jiminny\\Traits\\GracefullyStoppable; use Jiminny\\Traits\\GracefullyStoppable; private function getRemainingScheduledEntities(bool $printStatus = false): int private function getRemainingScheduledEntities(bool $printStatus = false): int { { $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget, true); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount( $this->updateTarget, QueuePriorityEnum::HIGH ); if ($printStatus) { if ($printStatus) { $this->line( $this->line(","depth":21,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"You said","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app/Component/ES/Listeners/UpdateMultipleTargetsListener.php","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"+2-1Lines changed: 2 additions & 1 deletion","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\\Component\\ES\\Listeners;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"namespace Jiminny\\Component\\ES\\Listeners;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\QueuePriorityEnum;","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Contracts\\ES\\Events\\UpdateMultipleEntities;","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Contracts\\ES\\Events\\UpdateMultipleEntities;","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Psr\\Log\\LoggerInterface;","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Psr\\Log\\LoggerInterface;","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getUpdateTargetValue(),","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getUpdateTargetValue(),","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getEntities(),","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getEntities(),","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->isPriority()","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL,","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":");","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":");","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app/Component/ES/Listeners/UpdateSingleTargetListener.php","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"+9-1Lines changed: 9 additions & 1 deletion","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Actions\\TrackElasticSearchOperations;","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Actions\\TrackElasticSearchOperations;","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch;","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch;","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder;","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder;","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\QueuePriorityEnum;","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Contracts\\ES\\Events\\UpdateSingleEntity;","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Contracts\\ES\\Events\\UpdateSingleEntity;","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Psr\\Log\\LoggerInterface;","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Psr\\Log\\LoggerInterface;","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"'entityId' => $event->getEntityId(),","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"'entityId' => $event->getEntityId(),","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"]);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"]);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/**","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* @important:","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* Synchronous event should eventually be deprecated.","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* Instant write operations are blocking and should be used sparingly.","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* It is much better in terms of performance to write 100 or 1000 documents at once,","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* and have one blocking reindex operation, instead of writing 10 documents synchronously.","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"*/","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"if ($event->isSyncEvent()) {","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"if ($event->isSyncEvent()) {","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$this->handleSyncEvent($event);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$this->handleSyncEvent($event);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AsyncUpdateElasticSearch::markEntityForUpdate(","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AsyncUpdateElasticSearch::markEntityForUpdate(","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getUpdateTargetValue(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getUpdateTargetValue(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getEntityId(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getEntityId(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->isPriority()","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL,","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":");","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":");","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app/Component/ES/Processor/Actions/UpsertDocumentsAction.php","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"+2-1Lines changed: 2 additions & 1 deletion","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Processor\\DTOs\\SimpleCollection;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\DTOs\\SimpleCollection;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\ResponseEvaluator;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\ResponseEvaluator;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\QueuePriorityEnum;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Exceptions\\InvalidDataException;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Exceptions\\InvalidDataException;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Sentry\\Laravel\\Facade as Sentry;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Sentry\\Laravel\\Facade as Sentry;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AsyncUpdateElasticSearch::markEntityForUpdate(","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AsyncUpdateElasticSearch::markEntityForUpdate(","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"entityType: $this->updateTarget,","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"entityType: $this->updateTarget,","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"entityId: (int) $document->getId(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"entityId: (int) $document->getId(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"withPriority: true","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"priority: QueuePriorityEnum::HIGH,","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":");","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":");","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app/Component/ES/Processor/DTOs/SelectionList.php","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"+54-17Lines changed: 54 additions & 17 deletions","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Original file line numberOriginal file lineDiff line numberDiff line change","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"namespace Jiminny\\Component\\ES\\Processor\\DTOs;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"namespace Jiminny\\Component\\ES\\Processor\\DTOs;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\QueuePriorityEnum;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/**","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/**","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* A very basic and simple collection of entity IDs.","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* A very basic and simple collection of entity IDs.","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"*/","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"*/","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"class SelectionList","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"class SelectionList","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function __construct(","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private const int DEFAULT_CHUNK = 200;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private readonly array $priorityEntityIdList = [],","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private readonly array $normalEntityIdList = [],","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private int $chunkSize = self::DEFAULT_CHUNK;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private readonly bool $isStaleChunkSelected = false,","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private bool $isStaleChunkSelected = false;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private readonly int $chunkSize = 200,","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private array $selectedEntityIds = [];","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":") {","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"// Do nothing","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function setChunkSize(int $chunkSize): void","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$this->chunkSize = $chunkSize;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function getAllIds(): array","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function markStale(): void","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"return array_merge($this->priorityEntityIdList, $this->normalEntityIdList);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$this->isStaleChunkSelected = true;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"}]...
|
4141898300521863576
|
-1126437240719860594
|
click
|
accessibility
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
Close tab
New Tab
Customize sidebar
Close Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
AI Chat settings
Close
WORK, Google Account: [EMAIL]
Main menu
New chat
Gemini
New Chat
Open menu for conversation actions.
Conversation with Gemini
Conversation with Gemini
Show the uploaded image in a lightbox
Copy prompt
You said Make a PR of changes Find potential issues and bottlenecks
You said
Make a PR of changes Find potential issues and bottlenecks
Listen
Show thinking
Gemini said
Gemini said
I can see you've uploaded a screenshot of a code diff, likely from a version control system given the red and green highlights. I would love to help you review the changes, spot bottlenecks, and help you draft a Pull Request.
However,
the image resolution is far too low for me to read.
It appears to be a completely zoomed-out view where the code has been reduced to tiny, illegible pixels. Because of this, I cannot extract any text or logic to analyze.
How You Can Share the Code
How You Can Share the Code
To help me review your code effectively, please try one of the following:
Paste the text directly:
Copy the specific code blocks (both the old and new versions if possible) and paste them directly into our chat.
Upload the files:
If the changes are extensive, you can upload the raw text or code files.
Take high-resolution screenshots:
If you must use images, take closer, readable screenshots of the specific functions or methods you want me to review.
Once you provide the readable code, I can dive right in to identify potential bugs, assess performance bottlenecks, and help you summarize the changes for your PR!
Good response
Bad response
Share & export
Copy
Show more options
Copy prompt
Edit
You said app/Component/ES/Listeners/UpdateMultipleTargetsListener.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\Component\ES\Listeners; namespace Jiminny\Component\ES\Listeners; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Contracts\ES\Events\UpdateMultipleEntities; use Jiminny\Contracts\ES\Events\UpdateMultipleEntities; use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface; AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntities(), $event->getEntities(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } } } app/Component/ES/Listeners/UpdateSingleTargetListener.php +9-1Lines changed: 9 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Actions\TrackElasticSearchOperations; use Jiminny\Component\ES\Actions\TrackElasticSearchOperations; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Contracts\ES\Events\UpdateSingleEntity; use Jiminny\Contracts\ES\Events\UpdateSingleEntity; use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface; 'entityId' => $event->getEntityId(), 'entityId' => $event->getEntityId(), ]); ]); /** * @important: * Synchronous event should eventually be deprecated. * Instant write operations are blocking and should be used sparingly. * It is much better in terms of performance to write 100 or 1000 documents at once, * and have one blocking reindex operation, instead of writing 10 documents synchronously. */ if ($event->isSyncEvent()) { if ($event->isSyncEvent()) { $this->handleSyncEvent($event); $this->handleSyncEvent($event); AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntityId(), $event->getEntityId(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } app/Component/ES/Processor/Actions/UpsertDocumentsAction.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SimpleCollection; use Jiminny\Component\ES\Processor\DTOs\SimpleCollection; use Jiminny\Component\ES\Processor\ResponseEvaluator; use Jiminny\Component\ES\Processor\ResponseEvaluator; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Exceptions\InvalidDataException; use Jiminny\Exceptions\InvalidDataException; use Sentry\Laravel\Facade as Sentry; use Sentry\Laravel\Facade as Sentry; AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( entityType: $this->updateTarget, entityType: $this->updateTarget, entityId: (int) $document->getId(), entityId: (int) $document->getId(), withPriority: true priority: QueuePriorityEnum::HIGH, ); ); } } app/Component/ES/Processor/DTOs/SelectionList.php +54-17Lines changed: 54 additions & 17 deletions Original file line numberOriginal file lineDiff line numberDiff line change namespace Jiminny\Component\ES\Processor\DTOs; namespace Jiminny\Component\ES\Processor\DTOs; use Jiminny\Component\ES\QueuePriorityEnum; /** /** * A very basic and simple collection of entity IDs. * A very basic and simple collection of entity IDs. */ */ class SelectionList class SelectionList { { public function __construct( private const int DEFAULT_CHUNK = 200; private readonly array $priorityEntityIdList = [], private readonly array $normalEntityIdList = [], private int $chunkSize = self::DEFAULT_CHUNK; private readonly bool $isStaleChunkSelected = false, private bool $isStaleChunkSelected = false; private readonly int $chunkSize = 200, private array $selectedEntityIds = []; ) { // Do nothing public function setChunkSize(int $chunkSize): void { $this->chunkSize = $chunkSize; } } public function getAllIds(): array public function markStale(): void { { return array_merge($this->priorityEntityIdList, $this->normalEntityIdList); $this->isStaleChunkSelected = true; } } public function count(): int public function addEntityList(string|QueuePriorityEnum $priority, array $entityIds): void { { return count($this->priorityEntityIdList) + count($this->normalEntityIdList); $priorityKey = $this->normalisePriority($priority); if (! array_key_exists($priorityKey, $this->selectedEntityIds)) { $this->selectedEntityIds[$priorityKey] = []; } $this->selectedEntityIds[$priorityKey] = array_merge($this->selectedEntityIds[$priorityKey], $entityIds); } } public function isEmpty(): bool /** * @return string[] */ public function getEntityListGroups(): array { { return empty($this->priorityEntityIdList) && empty($this->normalEntityIdList); return array_keys($this->selectedEntityIds); } } public function getHighPriorityEntityIds(): array public function getEntityListItemsByGroup(string|QueuePriorityEnum $priority): array { { return $this->priorityEntityIdList; $priorityKey = $this->normalisePriority($priority); return $this->selectedEntityIds[$priorityKey] ?? []; } } public function getNormalPriorityEntityId(): array public function getAllIds(): array { { return $this->normalEntityIdList; $allIds = []; foreach ($this->selectedEntityIds as $entityIds) { $allIds = array_merge($allIds, $entityIds); } return $allIds; } public function count(): int { return array_sum( array_map('count', $this->selectedEntityIds) ); } public function isEmpty(): bool { return $this->count() === 0; } } public function isStaleChunkSelected(): bool public function isStaleChunkSelected(): bool { { return $this->count() >= $this->chunkSize; return $this->count() >= $this->chunkSize; } } private function normalisePriority(string|QueuePriorityEnum $priority): string { return $priority instanceof QueuePriorityEnum ? $priority->value : $priority; } } } app/Component/ES/Processor/Traits/SelectEntityListTrait.php +27-4Lines changed: 27 additions & 4 deletions Original file line numberOriginal file lineDiff line numberDiff line change use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; /** /** * Build the correct source list name for the type of entity and priority * Build the correct source list name for the type of entity and priority */ */ trait SelectEntityListTrait trait SelectEntityListTrait { { /** * Highest priority queue for data requiring near-instant availability. * Very few entities should be added here, only when absolutely necessary. */ private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; /** * Normal priority queue for normal application operations. * Almost all update events should pass through this queue */ private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; protected static function selectTargetList(string $entityType, bool $withPriority = false): string /** { * Nonblocking low priority queue. This queue will be consumed only when there is nothing * with higher priority. * * This queue will be used for operations such as es:reset-async */ private const string ENTITIES_LOW_PRIORITIES_LIST = '%s-for-update-low'; protected static function selectTargetList( string $entityType, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { if (! in_array($entityType, UpdateTarget::allowedTargets())) { if (! in_array($entityType, UpdateTarget::allowedTargets())) { throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); } } if ($withPriority) { if ($priority->isHigh()) { Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); } } if ($priority->isLow()) { return sprintf(self::ENTITIES_LOW_PRIORITIES_LIST, $entityType); } return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); } } } } app/Component/ES/Processor/TargetEntitiesSelector.php +26-21Lines changed: 26 additions & 21 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SelectionList; use Jiminny\Component\ES\Processor\DTOs\SelectionList; use Jiminny\Component\ES\Processor\Traits\ExtractIdsTrait; use Jiminny\Component\ES\Processor\Traits\ExtractIdsTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\QueuePriorityEnum; /** /** * This class supplies a list of entities pending an update. * This class supplies a list of entities pending an update. public function select(): SelectionList public function select(): SelectionList { { $staleWorkEntityIds = $this->getStaleChunk(); $selectionList = new SelectionList(); $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $staleWorkEntityIds = $this->getStaleChunk(); if (count($staleWorkEntityIds) > 0) { if (count($staleWorkEntityIds) > 0) { return new SelectionList( /** priorityEntityIdList: $staleWorkEntityIds, * Stale chunks are treated as high priority isStaleChunkSelected: true, */ chunkSize: ChunkSize::getStaleChunkSize($this->updateTarget), $selectionList->markStale(); ); $selectionList->addEntityList(QueuePriorityEnum::HIGH, $staleWorkEntityIds); $selectionList->setChunkSize(ChunkSize::getStaleChunkSize($this->updateTarget)); return $selectionList; } } $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $selectionList->setChunkSize($mainChunkSize); $priorityEntityIdsList = $this->extractIdsFromSet( $priorityEntityIdsList = $this->extractIds(QueuePriorityEnum::HIGH, $mainChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, true), $selectionList->addEntityList(QueuePriorityEnum::HIGH, $priorityEntityIdsList); $mainChunkSize, ); $normalEntityIdsList = []; $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); if ($normalEntityChunkSize > 0) { if ($normalEntityChunkSize > 0) { $normalEntityIdsList = $this->extractIdsFromSet( $normalEntityIdsList = $this->extractIds(QueuePriorityEnum::NORMAL, $normalEntityChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, false), $selectionList->addEntityList(QueuePriorityEnum::NORMAL, $normalEntityIdsList); $normalEntityChunkSize ); } } return new SelectionList( return $selectionList; priorityEntityIdList: $priorityEntityIdsList, normalEntityIdList: $normalEntityIdsList, chunkSize: $mainChunkSize ); } } private function getStaleChunk(): array private function getStaleChunk(): array return []; return []; } } private function extractIds(QueuePriorityEnum $priority, int $chunkSize): array { return $this->extractIdsFromSet( AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, $priority), $chunkSize ); } } } app/Component/ES/AsyncUpdateElasticSearch.php +17-10Lines changed: 17 additions & 10 deletions Original file line numberOriginal file lineDiff line numberDiff line change * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * and other activity related data * and other activity related data */ */ public static function markEntityForUpdate(string $entityType, int $entityId, bool $withPriority = false): void public static function markEntityForUpdate( { string $entityType, $targetList = self::selectTargetList($entityType, $withPriority); int $entityId, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { $targetList = self::selectTargetList($entityType, $priority); Redis::sadd($targetList, $entityId); Redis::sadd($targetList, $entityId); Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ 'entityType' => $entityType, 'entityType' => $entityType, 'entityId' => $entityId, 'entityId' => $entityId, 'collectionKey' => $targetList, 'collectionKey' => $targetList, 'withPriority' => $withPriority, 'priority' => $priority->value, ]); ]); } } public static function bulkMarkEntitiesForUpdate( public static function bulkMarkEntitiesForUpdate( string $entityType, string $entityType, array $entityIds, array $entityIds, bool $withPriority = false QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { ): void { if (empty($entityIds)) { if (empty($entityIds)) { return; return; } } $targetList = self::selectTargetList($entityType, $withPriority); $targetList = self::selectTargetList($entityType, $priority); Redis::saddarray($targetList, $entityIds); Redis::saddarray($targetList, $entityIds); } } * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Takes priority into consideration. * Takes priority into consideration. */ */ public static function getEntitiesSourceList(string $updateTarget, $priority = false): string public static function getEntitiesSourceList( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { return self::selectTargetList($updateTarget, $priority); return self::selectTargetList($updateTarget, $priority); } } /** /** * Externally called helper methods * Externally called helper methods * - count and flush * - count and flush */ */ public static function getEntitiesListCount(string $updateTarget, $priority = false): int public static function getEntitiesListCount( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): int { $targetList = self::selectTargetList($updateTarget, $priority); $targetList = self::selectTargetList($updateTarget, $priority); return Redis::scard($targetList); return Redis::scard($targetList); app/Component/ES/QueuePriorityEnum.php +40Lines changed: 40 additions & 0 deletions Original file line numberOriginal file lineDiff line numberDiff line change <?php declare(strict_types=1); namespace Jiminny\Component\ES; use Jiminny\Exceptions\InvalidArgumentException; enum QueuePriorityEnum: string { case HIGH = 'high'; case NORMAL = 'normal'; case LOW = 'low'; public static function tryFromString(string $value): self { if (! self::isValid($value)) { throw new InvalidArgumentException( sprintf('Invalid queue priority "%s" selected', $value) ); } return self::tryFrom($value); } public static function isValid(string $value): bool { return self::tryFrom($value) !== null; } public function isLow(): bool { return $this === self::LOW; } public function isHigh(): bool { return $this === self::HIGH; } } app/Component/ES/UpdateProcessManager.php +12-9Lines changed: 12 additions & 9 deletions Original file line numberOriginal file lineDiff line numberDiff line change if ($selectionList->isEmpty()) { if ($selectionList->isEmpty()) { return false; return false; } } /** /** * A stale chunk will always be smaller than a regular chunk. * A stale chunk will always be smaller than a regular chunk. * That doesn't mean there aren't any other scheduled entities for processing * That doesn't mean there aren't any other scheduled entities for processing private function rescheduleThrottledEntities(SelectionList $selectionList): void private function rescheduleThrottledEntities(SelectionList $selectionList): void { { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $groups = $selectionList->getEntityListGroups(); $this->updateTarget, foreach ($groups as $eachGroup) { $selectionList->getNormalPriorityEntityId() $groupEntityIds = $selectionList->getEntityListItemsByGroup($eachGroup); ); if (! empty($groupEntityIds)) { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $this->updateTarget, entityType: $this->updateTarget, $selectionList->getHighPriorityEntityIds(), entityIds: $groupEntityIds, true priority: QueuePriorityEnum::tryFromString($eachGroup) ); ); } } } } } } app/Console/Commands/Elasticsearch/AsyncUpdateEsEntities.php +9-3Lines changed: 9 additions & 3 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Illuminate\Support\Str; use Illuminate\Support\Str; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Component\ES\UpdateProcessManager; use Jiminny\Component\ES\UpdateProcessManager; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Traits\GracefullyStoppable; use Jiminny\Traits\GracefullyStoppable; Redis::set($gaugeLockName, true); Redis::set($gaugeLockName, true); Redis::expire($gaugeLockName, 60); Redis::expire($gaugeLockName, 60); $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::HIGH), ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update', $updateTarget), stat: sprintf('jiminny.%s-for-update', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::NORMAL), ); ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), stat: sprintf('jiminny.%s-for-update-low', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, true), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::LOW), ); ); } } app/Console/Commands/Elasticsearch/ResetAsyncElasticSearchCommand.php +5-1Lines changed: 5 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\Traits\ValidateUpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\ValidateUpdateTargetTrait; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Component\ES\Repositories\EsResetRepositoryInterface; use Jiminny\Component\ES\Repositories\EsResetRepositoryInterface; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Traits\GracefullyStoppable; use Jiminny\Traits\GracefullyStoppable; private function getRemainingScheduledEntities(bool $printStatus = false): int private function getRemainingScheduledEntities(bool $printStatus = false): int { { $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget, true); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount( $this->updateTarget, QueuePriorityEnum::HIGH ); if ($printStatus) { if ($printStatus) { $this->line( $this->line(
You said
app/Component/ES/Listeners/UpdateMultipleTargetsListener.php
+2-1Lines changed: 2 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\Component\ES\Listeners;
namespace Jiminny\Component\ES\Listeners;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\QueuePriorityEnum;
use Jiminny\Contracts\ES\Events\UpdateMultipleEntities;
use Jiminny\Contracts\ES\Events\UpdateMultipleEntities;
use Psr\Log\LoggerInterface;
use Psr\Log\LoggerInterface;
AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(
AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(
$event->getUpdateTargetValue(),
$event->getUpdateTargetValue(),
$event->getEntities(),
$event->getEntities(),
$event->isPriority()
$event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL,
);
);
}
}
}
}
app/Component/ES/Listeners/UpdateSingleTargetListener.php
+9-1Lines changed: 9 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Actions\TrackElasticSearchOperations;
use Jiminny\Component\ES\Actions\TrackElasticSearchOperations;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\Processor\EntityQueryBuilder;
use Jiminny\Component\ES\Processor\EntityQueryBuilder;
use Jiminny\Component\ES\QueuePriorityEnum;
use Jiminny\Contracts\ES\Events\UpdateSingleEntity;
use Jiminny\Contracts\ES\Events\UpdateSingleEntity;
use Psr\Log\LoggerInterface;
use Psr\Log\LoggerInterface;
'entityId' => $event->getEntityId(),
'entityId' => $event->getEntityId(),
]);
]);
/**
* @important:
* Synchronous event should eventually be deprecated.
* Instant write operations are blocking and should be used sparingly.
* It is much better in terms of performance to write 100 or 1000 documents at once,
* and have one blocking reindex operation, instead of writing 10 documents synchronously.
*/
if ($event->isSyncEvent()) {
if ($event->isSyncEvent()) {
$this->handleSyncEvent($event);
$this->handleSyncEvent($event);
AsyncUpdateElasticSearch::markEntityForUpdate(
AsyncUpdateElasticSearch::markEntityForUpdate(
$event->getUpdateTargetValue(),
$event->getUpdateTargetValue(),
$event->getEntityId(),
$event->getEntityId(),
$event->isPriority()
$event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL,
);
);
}
}
app/Component/ES/Processor/Actions/UpsertDocumentsAction.php
+2-1Lines changed: 2 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SimpleCollection;
use Jiminny\Component\ES\Processor\DTOs\SimpleCollection;
use Jiminny\Component\ES\Processor\ResponseEvaluator;
use Jiminny\Component\ES\Processor\ResponseEvaluator;
use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait;
use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait;
use Jiminny\Component\ES\QueuePriorityEnum;
use Jiminny\Exceptions\InvalidDataException;
use Jiminny\Exceptions\InvalidDataException;
use Sentry\Laravel\Facade as Sentry;
use Sentry\Laravel\Facade as Sentry;
AsyncUpdateElasticSearch::markEntityForUpdate(
AsyncUpdateElasticSearch::markEntityForUpdate(
entityType: $this->updateTarget,
entityType: $this->updateTarget,
entityId: (int) $document->getId(),
entityId: (int) $document->getId(),
withPriority: true
priority: QueuePriorityEnum::HIGH,
);
);
}
}
app/Component/ES/Processor/DTOs/SelectionList.php
+54-17Lines changed: 54 additions & 17 deletions
Original file line numberOriginal file lineDiff line numberDiff line change
namespace Jiminny\Component\ES\Processor\DTOs;
namespace Jiminny\Component\ES\Processor\DTOs;
use Jiminny\Component\ES\QueuePriorityEnum;
/**
/**
* A very basic and simple collection of entity IDs.
* A very basic and simple collection of entity IDs.
*/
*/
class SelectionList
class SelectionList
{
{
public function __construct(
private const int DEFAULT_CHUNK = 200;
private readonly array $priorityEntityIdList = [],
private readonly array $normalEntityIdList = [],
private int $chunkSize = self::DEFAULT_CHUNK;
private readonly bool $isStaleChunkSelected = false,
private bool $isStaleChunkSelected = false;
private readonly int $chunkSize = 200,
private array $selectedEntityIds = [];
) {
// Do nothing
public function setChunkSize(int $chunkSize): void
{
$this->chunkSize = $chunkSize;
}
}
public function getAllIds(): array
public function markStale(): void
{
{
return array_merge($this->priorityEntityIdList, $this->normalEntityIdList);
$this->isStaleChunkSelected = true;
}...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
55696
|
1934
|
0
|
2026-05-19T06:41:56.116766+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779172916116_m1.jpg...
|
Firefox
|
JY-20808 low priority indexing queue by Vasil-Jimi JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app — Work...
|
1
|
github.com/jiminny/app/pull/12082/changes#diff-49a github.com/jiminny/app/pull/12082/changes#diff-49a79d99c97caf7fc27ecb1dbacab5a29d871822caa0db0c71e94957c28c87af...
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
Close tab
New Tab
Customize sidebar
Close Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
AI Chat settings
Close
WORK, Google Account: [EMAIL]
Main menu
New chat
Gemini
New Chat
Open menu for conversation actions.
Conversation with Gemini
Conversation with Gemini
Show the uploaded image in a lightbox
Copy prompt
You said Make a PR of changes Find potential issues and bottlenecks
You said
Make a PR of changes Find potential issues and bottlenecks
Listen
Show thinking
Gemini said
Gemini said
I can see you've uploaded a screenshot of a code diff, likely from a version control system given the red and green highlights. I would love to help you review the changes, spot bottlenecks, and help you draft a Pull Request.
However,
the image resolution is far too low for me to read.
It appears to be a completely zoomed-out view where the code has been reduced to tiny, illegible pixels. Because of this, I cannot extract any text or logic to analyze.
How You Can Share the Code
How You Can Share the Code
To help me review your code effectively, please try one of the following:
Paste the text directly:
Copy the specific code blocks (both the old and new versions if possible) and paste them directly into our chat.
Upload the files:
If the changes are extensive, you can upload the raw text or code files.
Take high-resolution screenshots:
If you must use images, take closer, readable screenshots of the specific functions or methods you want me to review.
Once you provide the readable code, I can dive right in to identify potential bugs, assess performance bottlenecks, and help you summarize the changes for your PR!
Good response
Bad response
Share & export
Copy
Show more options
Copy prompt
Edit
You said app/Component/ES/Listeners/UpdateMultipleTargetsListener.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\Component\ES\Listeners; namespace Jiminny\Component\ES\Listeners; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Contracts\ES\Events\UpdateMultipleEntities; use Jiminny\Contracts\ES\Events\UpdateMultipleEntities; use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface; AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntities(), $event->getEntities(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } } } app/Component/ES/Listeners/UpdateSingleTargetListener.php +9-1Lines changed: 9 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Actions\TrackElasticSearchOperations; use Jiminny\Component\ES\Actions\TrackElasticSearchOperations; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Contracts\ES\Events\UpdateSingleEntity; use Jiminny\Contracts\ES\Events\UpdateSingleEntity; use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface; 'entityId' => $event->getEntityId(), 'entityId' => $event->getEntityId(), ]); ]); /** * @important: * Synchronous event should eventually be deprecated. * Instant write operations are blocking and should be used sparingly. * It is much better in terms of performance to write 100 or 1000 documents at once, * and have one blocking reindex operation, instead of writing 10 documents synchronously. */ if ($event->isSyncEvent()) { if ($event->isSyncEvent()) { $this->handleSyncEvent($event); $this->handleSyncEvent($event); AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntityId(), $event->getEntityId(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } app/Component/ES/Processor/Actions/UpsertDocumentsAction.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SimpleCollection; use Jiminny\Component\ES\Processor\DTOs\SimpleCollection; use Jiminny\Component\ES\Processor\ResponseEvaluator; use Jiminny\Component\ES\Processor\ResponseEvaluator; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Exceptions\InvalidDataException; use Jiminny\Exceptions\InvalidDataException; use Sentry\Laravel\Facade as Sentry; use Sentry\Laravel\Facade as Sentry; AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( entityType: $this->updateTarget, entityType: $this->updateTarget, entityId: (int) $document->getId(), entityId: (int) $document->getId(), withPriority: true priority: QueuePriorityEnum::HIGH, ); ); } } app/Component/ES/Processor/DTOs/SelectionList.php +54-17Lines changed: 54 additions & 17 deletions Original file line numberOriginal file lineDiff line numberDiff line change namespace Jiminny\Component\ES\Processor\DTOs; namespace Jiminny\Component\ES\Processor\DTOs; use Jiminny\Component\ES\QueuePriorityEnum; /** /** * A very basic and simple collection of entity IDs. * A very basic and simple collection of entity IDs. */ */ class SelectionList class SelectionList { { public function __construct( private const int DEFAULT_CHUNK = 200; private readonly array $priorityEntityIdList = [], private readonly array $normalEntityIdList = [], private int $chunkSize = self::DEFAULT_CHUNK; private readonly bool $isStaleChunkSelected = false, private bool $isStaleChunkSelected = false; private readonly int $chunkSize = 200, private array $selectedEntityIds = []; ) { // Do nothing public function setChunkSize(int $chunkSize): void { $this->chunkSize = $chunkSize; } } public function getAllIds(): array public function markStale(): void { { return array_merge($this->priorityEntityIdList, $this->normalEntityIdList); $this->isStaleChunkSelected = true; } } public function count(): int public function addEntityList(string|QueuePriorityEnum $priority, array $entityIds): void { { return count($this->priorityEntityIdList) + count($this->normalEntityIdList); $priorityKey = $this->normalisePriority($priority); if (! array_key_exists($priorityKey, $this->selectedEntityIds)) { $this->selectedEntityIds[$priorityKey] = []; } $this->selectedEntityIds[$priorityKey] = array_merge($this->selectedEntityIds[$priorityKey], $entityIds); } } public function isEmpty(): bool /** * @return string[] */ public function getEntityListGroups(): array { { return empty($this->priorityEntityIdList) && empty($this->normalEntityIdList); return array_keys($this->selectedEntityIds); } } public function getHighPriorityEntityIds(): array public function getEntityListItemsByGroup(string|QueuePriorityEnum $priority): array { { return $this->priorityEntityIdList; $priorityKey = $this->normalisePriority($priority); return $this->selectedEntityIds[$priorityKey] ?? []; } } public function getNormalPriorityEntityId(): array public function getAllIds(): array { { return $this->normalEntityIdList; $allIds = []; foreach ($this->selectedEntityIds as $entityIds) { $allIds = array_merge($allIds, $entityIds); } return $allIds; } public function count(): int { return array_sum( array_map('count', $this->selectedEntityIds) ); } public function isEmpty(): bool { return $this->count() === 0; } } public function isStaleChunkSelected(): bool public function isStaleChunkSelected(): bool { { return $this->count() >= $this->chunkSize; return $this->count() >= $this->chunkSize; } } private function normalisePriority(string|QueuePriorityEnum $priority): string { return $priority instanceof QueuePriorityEnum ? $priority->value : $priority; } } } app/Component/ES/Processor/Traits/SelectEntityListTrait.php +27-4Lines changed: 27 additions & 4 deletions Original file line numberOriginal file lineDiff line numberDiff line change use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; /** /** * Build the correct source list name for the type of entity and priority * Build the correct source list name for the type of entity and priority */ */ trait SelectEntityListTrait trait SelectEntityListTrait { { /** * Highest priority queue for data requiring near-instant availability. * Very few entities should be added here, only when absolutely necessary. */ private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; /** * Normal priority queue for normal application operations. * Almost all update events should pass through this queue */ private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; protected static function selectTargetList(string $entityType, bool $withPriority = false): string /** { * Nonblocking low priority queue. This queue will be consumed only when there is nothing * with higher priority. * * This queue will be used for operations such as es:reset-async */ private const string ENTITIES_LOW_PRIORITIES_LIST = '%s-for-update-low'; protected static function selectTargetList( string $entityType, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { if (! in_array($entityType, UpdateTarget::allowedTargets())) { if (! in_array($entityType, UpdateTarget::allowedTargets())) { throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); } } if ($withPriority) { if ($priority->isHigh()) { Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); } } if ($priority->isLow()) { return sprintf(self::ENTITIES_LOW_PRIORITIES_LIST, $entityType); } return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); } } } } app/Component/ES/Processor/TargetEntitiesSelector.php +26-21Lines changed: 26 additions & 21 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SelectionList; use Jiminny\Component\ES\Processor\DTOs\SelectionList; use Jiminny\Component\ES\Processor\Traits\ExtractIdsTrait; use Jiminny\Component\ES\Processor\Traits\ExtractIdsTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\QueuePriorityEnum; /** /** * This class supplies a list of entities pending an update. * This class supplies a list of entities pending an update. public function select(): SelectionList public function select(): SelectionList { { $staleWorkEntityIds = $this->getStaleChunk(); $selectionList = new SelectionList(); $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $staleWorkEntityIds = $this->getStaleChunk(); if (count($staleWorkEntityIds) > 0) { if (count($staleWorkEntityIds) > 0) { return new SelectionList( /** priorityEntityIdList: $staleWorkEntityIds, * Stale chunks are treated as high priority isStaleChunkSelected: true, */ chunkSize: ChunkSize::getStaleChunkSize($this->updateTarget), $selectionList->markStale(); ); $selectionList->addEntityList(QueuePriorityEnum::HIGH, $staleWorkEntityIds); $selectionList->setChunkSize(ChunkSize::getStaleChunkSize($this->updateTarget)); return $selectionList; } } $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $selectionList->setChunkSize($mainChunkSize); $priorityEntityIdsList = $this->extractIdsFromSet( $priorityEntityIdsList = $this->extractIds(QueuePriorityEnum::HIGH, $mainChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, true), $selectionList->addEntityList(QueuePriorityEnum::HIGH, $priorityEntityIdsList); $mainChunkSize, ); $normalEntityIdsList = []; $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); if ($normalEntityChunkSize > 0) { if ($normalEntityChunkSize > 0) { $normalEntityIdsList = $this->extractIdsFromSet( $normalEntityIdsList = $this->extractIds(QueuePriorityEnum::NORMAL, $normalEntityChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, false), $selectionList->addEntityList(QueuePriorityEnum::NORMAL, $normalEntityIdsList); $normalEntityChunkSize ); } } return new SelectionList( return $selectionList; priorityEntityIdList: $priorityEntityIdsList, normalEntityIdList: $normalEntityIdsList, chunkSize: $mainChunkSize ); } } private function getStaleChunk(): array private function getStaleChunk(): array return []; return []; } } private function extractIds(QueuePriorityEnum $priority, int $chunkSize): array { return $this->extractIdsFromSet( AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, $priority), $chunkSize ); } } } app/Component/ES/AsyncUpdateElasticSearch.php +17-10Lines changed: 17 additions & 10 deletions Original file line numberOriginal file lineDiff line numberDiff line change * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * and other activity related data * and other activity related data */ */ public static function markEntityForUpdate(string $entityType, int $entityId, bool $withPriority = false): void public static function markEntityForUpdate( { string $entityType, $targetList = self::selectTargetList($entityType, $withPriority); int $entityId, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { $targetList = self::selectTargetList($entityType, $priority); Redis::sadd($targetList, $entityId); Redis::sadd($targetList, $entityId); Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ 'entityType' => $entityType, 'entityType' => $entityType, 'entityId' => $entityId, 'entityId' => $entityId, 'collectionKey' => $targetList, 'collectionKey' => $targetList, 'withPriority' => $withPriority, 'priority' => $priority->value, ]); ]); } } public static function bulkMarkEntitiesForUpdate( public static function bulkMarkEntitiesForUpdate( string $entityType, string $entityType, array $entityIds, array $entityIds, bool $withPriority = false QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { ): void { if (empty($entityIds)) { if (empty($entityIds)) { return; return; } } $targetList = self::selectTargetList($entityType, $withPriority); $targetList = self::selectTargetList($entityType, $priority); Redis::saddarray($targetList, $entityIds); Redis::saddarray($targetList, $entityIds); } } * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Takes priority into consideration. * Takes priority into consideration. */ */ public static function getEntitiesSourceList(string $updateTarget, $priority = false): string public static function getEntitiesSourceList( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { return self::selectTargetList($updateTarget, $priority); return self::selectTargetList($updateTarget, $priority); } } /** /** * Externally called helper methods * Externally called helper methods * - count and flush * - count and flush */ */ public static function getEntitiesListCount(string $updateTarget, $priority = false): int public static function getEntitiesListCount( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): int { $targetList = self::selectTargetList($updateTarget, $priority); $targetList = self::selectTargetList($updateTarget, $priority); return Redis::scard($targetList); return Redis::scard($targetList); app/Component/ES/QueuePriorityEnum.php +40Lines changed: 40 additions & 0 deletions Original file line numberOriginal file lineDiff line numberDiff line change <?php declare(strict_types=1); namespace Jiminny\Component\ES; use Jiminny\Exceptions\InvalidArgumentException; enum QueuePriorityEnum: string { case HIGH = 'high'; case NORMAL = 'normal'; case LOW = 'low'; public static function tryFromString(string $value): self { if (! self::isValid($value)) { throw new InvalidArgumentException( sprintf('Invalid queue priority "%s" selected', $value) ); } return self::tryFrom($value); } public static function isValid(string $value): bool { return self::tryFrom($value) !== null; } public function isLow(): bool { return $this === self::LOW; } public function isHigh(): bool { return $this === self::HIGH; } } app/Component/ES/UpdateProcessManager.php +12-9Lines changed: 12 additions & 9 deletions Original file line numberOriginal file lineDiff line numberDiff line change if ($selectionList->isEmpty()) { if ($selectionList->isEmpty()) { return false; return false; } } /** /** * A stale chunk will always be smaller than a regular chunk. * A stale chunk will always be smaller than a regular chunk. * That doesn't mean there aren't any other scheduled entities for processing * That doesn't mean there aren't any other scheduled entities for processing private function rescheduleThrottledEntities(SelectionList $selectionList): void private function rescheduleThrottledEntities(SelectionList $selectionList): void { { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $groups = $selectionList->getEntityListGroups(); $this->updateTarget, foreach ($groups as $eachGroup) { $selectionList->getNormalPriorityEntityId() $groupEntityIds = $selectionList->getEntityListItemsByGroup($eachGroup); ); if (! empty($groupEntityIds)) { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $this->updateTarget, entityType: $this->updateTarget, $selectionList->getHighPriorityEntityIds(), entityIds: $groupEntityIds, true priority: QueuePriorityEnum::tryFromString($eachGroup) ); ); } } } } } } app/Console/Commands/Elasticsearch/AsyncUpdateEsEntities.php +9-3Lines changed: 9 additions & 3 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Illuminate\Support\Str; use Illuminate\Support\Str; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Component\ES\UpdateProcessManager; use Jiminny\Component\ES\UpdateProcessManager; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Traits\GracefullyStoppable; use Jiminny\Traits\GracefullyStoppable; Redis::set($gaugeLockName, true); Redis::set($gaugeLockName, true); Redis::expire($gaugeLockName, 60); Redis::expire($gaugeLockName, 60); $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::HIGH), ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update', $updateTarget), stat: sprintf('jiminny.%s-for-update', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::NORMAL), ); ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), stat: sprintf('jiminny.%s-for-update-low', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, true), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::LOW), ); ); } } app/Console/Commands/Elasticsearch/ResetAsyncElasticSearchCommand.php +5-1Lines changed: 5 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\Traits\ValidateUpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\ValidateUpdateTargetTrait; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Component\ES\Repositories\EsResetRepositoryInterface; use Jiminny\Component\ES\Repositories\EsResetRepositoryInterface; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Traits\GracefullyStoppable; use Jiminny\Traits\GracefullyStoppable; private function getRemainingScheduledEntities(bool $printStatus = false): int private function getRemainingScheduledEntities(bool $printStatus = false): int { { $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget, true); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount( $this->updateTarget, QueuePriorityEnum::HIGH ); if ($printStatus) { if ($printStatus) { $this->line( $this->line(
You said
app/Component/ES/Listeners/UpdateMultipleTargetsListener.php
+2-1Lines changed: 2 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\Component\ES\Listeners;
namespace Jiminny\Component\ES\Listeners;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\QueuePriorityEnum;
use Jiminny\Contracts\ES\Events\UpdateMultipleEntities;
use Jiminny\Contracts\ES\Events\UpdateMultipleEntities;
use Psr\Log\LoggerInterface;
use Psr\Log\LoggerInterface;
AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(
AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(
$event->getUpdateTargetValue(),
$event->getUpdateTargetValue(),
$event->getEntities(),
$event->getEntities(),
$event->isPriority()
$event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL,
);
);
}
}
}
}
app/Component/ES/Listeners/UpdateSingleTargetListener.php
+9-1Lines changed: 9 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Actions\TrackElasticSearchOperations;
use Jiminny\Component\ES\Actions\TrackElasticSearchOperations;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\Processor\EntityQueryBuilder;
use Jiminny\Component\ES\Processor\EntityQueryBuilder;
use Jiminny\Component\ES\QueuePriorityEnum;
use Jiminny\Contracts\ES\Events\UpdateSingleEntity;
use Jiminny\Contracts\ES\Events\UpdateSingleEntity;
use Psr\Log\LoggerInterface;
use Psr\Log\LoggerInterface;
'entityId' => $event->getEntityId(),
'entityId' => $event->getEntityId(),
]);
]);
/**
* @important:
* Synchronous event should eventually be deprecated.
* Instant write operations are blocking and should be used sparingly.
* It is much better in terms of performance to write 100 or 1000 documents at once,
* and have one blocking reindex operation, instead of writing 10 documents synchronously.
*/
if ($event->isSyncEvent()) {
if ($event->isSyncEvent()) {
$this->handleSyncEvent($event);
$this->handleSyncEvent($event);
AsyncUpdateElasticSearch::markEntityForUpdate(
AsyncUpdateElasticSearch::markEntityForUpdate(
$event->getUpdateTargetValue(),
$event->getUpdateTargetValue(),
$event->getEntityId(),
$event->getEntityId(),
$event->isPriority()
$event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL,...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New Tab","depth":4,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Close Google Gemini (⌃X)","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Tabs from other devices","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"AI Chat settings","depth":7,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Close","depth":7,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"WORK, Google Account: lukas.kovalik@jiminny.com","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Main menu","depth":12,"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New chat","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Gemini","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"New Chat","depth":12,"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Open menu for conversation actions.","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXHeading","text":"Conversation with Gemini","depth":15,"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Conversation with Gemini","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Show the uploaded image in a lightbox","depth":21,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy prompt","depth":21,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"You said Make a PR of changes Find potential issues and bottlenecks","depth":21,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"You said","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Make a PR of changes Find potential issues and bottlenecks","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Listen","depth":22,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Show thinking","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Gemini said","depth":20,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Gemini said","depth":21,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"I can see you've uploaded a screenshot of a code diff, likely from a version control system given the red and green highlights. I would love to help you review the changes, spot bottlenecks, and help you draft a Pull Request.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"However,","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"the image resolution is far too low for me to read.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"It appears to be a completely zoomed-out view where the code has been reduced to tiny, illegible pixels. Because of this, I cannot extract any text or logic to analyze.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"How You Can Share the Code","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"How You Can Share the Code","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"To help me review your code effectively, please try one of the following:","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Paste the text directly:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Copy the specific code blocks (both the old and new versions if possible) and paste them directly into our chat.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Upload the files:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"If the changes are extensive, you can upload the raw text or code files.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Take high-resolution screenshots:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"If you must use images, take closer, readable screenshots of the specific functions or methods you want me to review.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Once you provide the readable code, I can dive right in to identify potential bugs, assess performance bottlenecks, and help you summarize the changes for your PR!","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Good response","depth":22,"on_screen":false,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Bad response","depth":22,"on_screen":false,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Share & export","depth":21,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy","depth":22,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Show more options","depth":21,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy prompt","depth":21,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Edit","depth":21,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"You said app/Component/ES/Listeners/UpdateMultipleTargetsListener.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\\Component\\ES\\Listeners; namespace Jiminny\\Component\\ES\\Listeners; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Contracts\\ES\\Events\\UpdateMultipleEntities; use Jiminny\\Contracts\\ES\\Events\\UpdateMultipleEntities; use Psr\\Log\\LoggerInterface; use Psr\\Log\\LoggerInterface; AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntities(), $event->getEntities(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } } } app/Component/ES/Listeners/UpdateSingleTargetListener.php +9-1Lines changed: 9 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Actions\\TrackElasticSearchOperations; use Jiminny\\Component\\ES\\Actions\\TrackElasticSearchOperations; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder; use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Contracts\\ES\\Events\\UpdateSingleEntity; use Jiminny\\Contracts\\ES\\Events\\UpdateSingleEntity; use Psr\\Log\\LoggerInterface; use Psr\\Log\\LoggerInterface; 'entityId' => $event->getEntityId(), 'entityId' => $event->getEntityId(), ]); ]); /** * @important: * Synchronous event should eventually be deprecated. * Instant write operations are blocking and should be used sparingly. * It is much better in terms of performance to write 100 or 1000 documents at once, * and have one blocking reindex operation, instead of writing 10 documents synchronously. */ if ($event->isSyncEvent()) { if ($event->isSyncEvent()) { $this->handleSyncEvent($event); $this->handleSyncEvent($event); AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntityId(), $event->getEntityId(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } app/Component/ES/Processor/Actions/UpsertDocumentsAction.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Processor\\DTOs\\SimpleCollection; use Jiminny\\Component\\ES\\Processor\\DTOs\\SimpleCollection; use Jiminny\\Component\\ES\\Processor\\ResponseEvaluator; use Jiminny\\Component\\ES\\Processor\\ResponseEvaluator; use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait; use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Exceptions\\InvalidDataException; use Jiminny\\Exceptions\\InvalidDataException; use Sentry\\Laravel\\Facade as Sentry; use Sentry\\Laravel\\Facade as Sentry; AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( entityType: $this->updateTarget, entityType: $this->updateTarget, entityId: (int) $document->getId(), entityId: (int) $document->getId(), withPriority: true priority: QueuePriorityEnum::HIGH, ); ); } } app/Component/ES/Processor/DTOs/SelectionList.php +54-17Lines changed: 54 additions & 17 deletions Original file line numberOriginal file lineDiff line numberDiff line change namespace Jiminny\\Component\\ES\\Processor\\DTOs; namespace Jiminny\\Component\\ES\\Processor\\DTOs; use Jiminny\\Component\\ES\\QueuePriorityEnum; /** /** * A very basic and simple collection of entity IDs. * A very basic and simple collection of entity IDs. */ */ class SelectionList class SelectionList { { public function __construct( private const int DEFAULT_CHUNK = 200; private readonly array $priorityEntityIdList = [], private readonly array $normalEntityIdList = [], private int $chunkSize = self::DEFAULT_CHUNK; private readonly bool $isStaleChunkSelected = false, private bool $isStaleChunkSelected = false; private readonly int $chunkSize = 200, private array $selectedEntityIds = []; ) { // Do nothing public function setChunkSize(int $chunkSize): void { $this->chunkSize = $chunkSize; } } public function getAllIds(): array public function markStale(): void { { return array_merge($this->priorityEntityIdList, $this->normalEntityIdList); $this->isStaleChunkSelected = true; } } public function count(): int public function addEntityList(string|QueuePriorityEnum $priority, array $entityIds): void { { return count($this->priorityEntityIdList) + count($this->normalEntityIdList); $priorityKey = $this->normalisePriority($priority); if (! array_key_exists($priorityKey, $this->selectedEntityIds)) { $this->selectedEntityIds[$priorityKey] = []; } $this->selectedEntityIds[$priorityKey] = array_merge($this->selectedEntityIds[$priorityKey], $entityIds); } } public function isEmpty(): bool /** * @return string[] */ public function getEntityListGroups(): array { { return empty($this->priorityEntityIdList) && empty($this->normalEntityIdList); return array_keys($this->selectedEntityIds); } } public function getHighPriorityEntityIds(): array public function getEntityListItemsByGroup(string|QueuePriorityEnum $priority): array { { return $this->priorityEntityIdList; $priorityKey = $this->normalisePriority($priority); return $this->selectedEntityIds[$priorityKey] ?? []; } } public function getNormalPriorityEntityId(): array public function getAllIds(): array { { return $this->normalEntityIdList; $allIds = []; foreach ($this->selectedEntityIds as $entityIds) { $allIds = array_merge($allIds, $entityIds); } return $allIds; } public function count(): int { return array_sum( array_map('count', $this->selectedEntityIds) ); } public function isEmpty(): bool { return $this->count() === 0; } } public function isStaleChunkSelected(): bool public function isStaleChunkSelected(): bool { { return $this->count() >= $this->chunkSize; return $this->count() >= $this->chunkSize; } } private function normalisePriority(string|QueuePriorityEnum $priority): string { return $priority instanceof QueuePriorityEnum ? $priority->value : $priority; } } } app/Component/ES/Processor/Traits/SelectEntityListTrait.php +27-4Lines changed: 27 additions & 4 deletions Original file line numberOriginal file lineDiff line numberDiff line change use Illuminate\\Support\\Facades\\Log; use Illuminate\\Support\\Facades\\Log; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Exceptions\\InvalidArgumentException; use Jiminny\\Exceptions\\InvalidArgumentException; /** /** * Build the correct source list name for the type of entity and priority * Build the correct source list name for the type of entity and priority */ */ trait SelectEntityListTrait trait SelectEntityListTrait { { /** * Highest priority queue for data requiring near-instant availability. * Very few entities should be added here, only when absolutely necessary. */ private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; /** * Normal priority queue for normal application operations. * Almost all update events should pass through this queue */ private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; protected static function selectTargetList(string $entityType, bool $withPriority = false): string /** { * Nonblocking low priority queue. This queue will be consumed only when there is nothing * with higher priority. * * This queue will be used for operations such as es:reset-async */ private const string ENTITIES_LOW_PRIORITIES_LIST = '%s-for-update-low'; protected static function selectTargetList( string $entityType, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { if (! in_array($entityType, UpdateTarget::allowedTargets())) { if (! in_array($entityType, UpdateTarget::allowedTargets())) { throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); } } if ($withPriority) { if ($priority->isHigh()) { Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); } } if ($priority->isLow()) { return sprintf(self::ENTITIES_LOW_PRIORITIES_LIST, $entityType); } return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); } } } } app/Component/ES/Processor/TargetEntitiesSelector.php +26-21Lines changed: 26 additions & 21 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Processor\\DTOs\\SelectionList; use Jiminny\\Component\\ES\\Processor\\DTOs\\SelectionList; use Jiminny\\Component\\ES\\Processor\\Traits\\ExtractIdsTrait; use Jiminny\\Component\\ES\\Processor\\Traits\\ExtractIdsTrait; use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait; use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait; use Jiminny\\Component\\ES\\QueuePriorityEnum; /** /** * This class supplies a list of entities pending an update. * This class supplies a list of entities pending an update. public function select(): SelectionList public function select(): SelectionList { { $staleWorkEntityIds = $this->getStaleChunk(); $selectionList = new SelectionList(); $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $staleWorkEntityIds = $this->getStaleChunk(); if (count($staleWorkEntityIds) > 0) { if (count($staleWorkEntityIds) > 0) { return new SelectionList( /** priorityEntityIdList: $staleWorkEntityIds, * Stale chunks are treated as high priority isStaleChunkSelected: true, */ chunkSize: ChunkSize::getStaleChunkSize($this->updateTarget), $selectionList->markStale(); ); $selectionList->addEntityList(QueuePriorityEnum::HIGH, $staleWorkEntityIds); $selectionList->setChunkSize(ChunkSize::getStaleChunkSize($this->updateTarget)); return $selectionList; } } $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $selectionList->setChunkSize($mainChunkSize); $priorityEntityIdsList = $this->extractIdsFromSet( $priorityEntityIdsList = $this->extractIds(QueuePriorityEnum::HIGH, $mainChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, true), $selectionList->addEntityList(QueuePriorityEnum::HIGH, $priorityEntityIdsList); $mainChunkSize, ); $normalEntityIdsList = []; $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); if ($normalEntityChunkSize > 0) { if ($normalEntityChunkSize > 0) { $normalEntityIdsList = $this->extractIdsFromSet( $normalEntityIdsList = $this->extractIds(QueuePriorityEnum::NORMAL, $normalEntityChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, false), $selectionList->addEntityList(QueuePriorityEnum::NORMAL, $normalEntityIdsList); $normalEntityChunkSize ); } } return new SelectionList( return $selectionList; priorityEntityIdList: $priorityEntityIdsList, normalEntityIdList: $normalEntityIdsList, chunkSize: $mainChunkSize ); } } private function getStaleChunk(): array private function getStaleChunk(): array return []; return []; } } private function extractIds(QueuePriorityEnum $priority, int $chunkSize): array { return $this->extractIdsFromSet( AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, $priority), $chunkSize ); } } } app/Component/ES/AsyncUpdateElasticSearch.php +17-10Lines changed: 17 additions & 10 deletions Original file line numberOriginal file lineDiff line numberDiff line change * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * and other activity related data * and other activity related data */ */ public static function markEntityForUpdate(string $entityType, int $entityId, bool $withPriority = false): void public static function markEntityForUpdate( { string $entityType, $targetList = self::selectTargetList($entityType, $withPriority); int $entityId, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { $targetList = self::selectTargetList($entityType, $priority); Redis::sadd($targetList, $entityId); Redis::sadd($targetList, $entityId); Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ 'entityType' => $entityType, 'entityType' => $entityType, 'entityId' => $entityId, 'entityId' => $entityId, 'collectionKey' => $targetList, 'collectionKey' => $targetList, 'withPriority' => $withPriority, 'priority' => $priority->value, ]); ]); } } public static function bulkMarkEntitiesForUpdate( public static function bulkMarkEntitiesForUpdate( string $entityType, string $entityType, array $entityIds, array $entityIds, bool $withPriority = false QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { ): void { if (empty($entityIds)) { if (empty($entityIds)) { return; return; } } $targetList = self::selectTargetList($entityType, $withPriority); $targetList = self::selectTargetList($entityType, $priority); Redis::saddarray($targetList, $entityIds); Redis::saddarray($targetList, $entityIds); } } * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Takes priority into consideration. * Takes priority into consideration. */ */ public static function getEntitiesSourceList(string $updateTarget, $priority = false): string public static function getEntitiesSourceList( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { return self::selectTargetList($updateTarget, $priority); return self::selectTargetList($updateTarget, $priority); } } /** /** * Externally called helper methods * Externally called helper methods * - count and flush * - count and flush */ */ public static function getEntitiesListCount(string $updateTarget, $priority = false): int public static function getEntitiesListCount( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): int { $targetList = self::selectTargetList($updateTarget, $priority); $targetList = self::selectTargetList($updateTarget, $priority); return Redis::scard($targetList); return Redis::scard($targetList); app/Component/ES/QueuePriorityEnum.php +40Lines changed: 40 additions & 0 deletions Original file line numberOriginal file lineDiff line numberDiff line change <?php declare(strict_types=1); namespace Jiminny\\Component\\ES; use Jiminny\\Exceptions\\InvalidArgumentException; enum QueuePriorityEnum: string { case HIGH = 'high'; case NORMAL = 'normal'; case LOW = 'low'; public static function tryFromString(string $value): self { if (! self::isValid($value)) { throw new InvalidArgumentException( sprintf('Invalid queue priority \"%s\" selected', $value) ); } return self::tryFrom($value); } public static function isValid(string $value): bool { return self::tryFrom($value) !== null; } public function isLow(): bool { return $this === self::LOW; } public function isHigh(): bool { return $this === self::HIGH; } } app/Component/ES/UpdateProcessManager.php +12-9Lines changed: 12 additions & 9 deletions Original file line numberOriginal file lineDiff line numberDiff line change if ($selectionList->isEmpty()) { if ($selectionList->isEmpty()) { return false; return false; } } /** /** * A stale chunk will always be smaller than a regular chunk. * A stale chunk will always be smaller than a regular chunk. * That doesn't mean there aren't any other scheduled entities for processing * That doesn't mean there aren't any other scheduled entities for processing private function rescheduleThrottledEntities(SelectionList $selectionList): void private function rescheduleThrottledEntities(SelectionList $selectionList): void { { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $groups = $selectionList->getEntityListGroups(); $this->updateTarget, foreach ($groups as $eachGroup) { $selectionList->getNormalPriorityEntityId() $groupEntityIds = $selectionList->getEntityListItemsByGroup($eachGroup); ); if (! empty($groupEntityIds)) { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $this->updateTarget, entityType: $this->updateTarget, $selectionList->getHighPriorityEntityIds(), entityIds: $groupEntityIds, true priority: QueuePriorityEnum::tryFromString($eachGroup) ); ); } } } } } } app/Console/Commands/Elasticsearch/AsyncUpdateEsEntities.php +9-3Lines changed: 9 additions & 3 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Illuminate\\Support\\Str; use Illuminate\\Support\\Str; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Component\\ES\\UpdateProcessManager; use Jiminny\\Component\\ES\\UpdateProcessManager; use Jiminny\\Exceptions\\InvalidArgumentException; use Jiminny\\Exceptions\\InvalidArgumentException; use Jiminny\\Traits\\GracefullyStoppable; use Jiminny\\Traits\\GracefullyStoppable; Redis::set($gaugeLockName, true); Redis::set($gaugeLockName, true); Redis::expire($gaugeLockName, 60); Redis::expire($gaugeLockName, 60); $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::HIGH), ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update', $updateTarget), stat: sprintf('jiminny.%s-for-update', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::NORMAL), ); ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), stat: sprintf('jiminny.%s-for-update-low', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, true), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::LOW), ); ); } } app/Console/Commands/Elasticsearch/ResetAsyncElasticSearchCommand.php +5-1Lines changed: 5 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder; use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder; use Jiminny\\Component\\ES\\Processor\\Traits\\ValidateUpdateTargetTrait; use Jiminny\\Component\\ES\\Processor\\Traits\\ValidateUpdateTargetTrait; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Component\\ES\\Repositories\\EsResetRepositoryInterface; use Jiminny\\Component\\ES\\Repositories\\EsResetRepositoryInterface; use Jiminny\\Exceptions\\InvalidArgumentException; use Jiminny\\Exceptions\\InvalidArgumentException; use Jiminny\\Traits\\GracefullyStoppable; use Jiminny\\Traits\\GracefullyStoppable; private function getRemainingScheduledEntities(bool $printStatus = false): int private function getRemainingScheduledEntities(bool $printStatus = false): int { { $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget, true); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount( $this->updateTarget, QueuePriorityEnum::HIGH ); if ($printStatus) { if ($printStatus) { $this->line( $this->line(","depth":21,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"You said","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app/Component/ES/Listeners/UpdateMultipleTargetsListener.php","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"+2-1Lines changed: 2 additions & 1 deletion","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\\Component\\ES\\Listeners;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"namespace Jiminny\\Component\\ES\\Listeners;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\QueuePriorityEnum;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Contracts\\ES\\Events\\UpdateMultipleEntities;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Contracts\\ES\\Events\\UpdateMultipleEntities;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Psr\\Log\\LoggerInterface;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Psr\\Log\\LoggerInterface;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getUpdateTargetValue(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getUpdateTargetValue(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getEntities(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getEntities(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->isPriority()","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL,","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":");","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":");","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app/Component/ES/Listeners/UpdateSingleTargetListener.php","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"+9-1Lines changed: 9 additions & 1 deletion","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Actions\\TrackElasticSearchOperations;","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Actions\\TrackElasticSearchOperations;","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch;","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch;","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder;","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder;","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\QueuePriorityEnum;","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Contracts\\ES\\Events\\UpdateSingleEntity;","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Contracts\\ES\\Events\\UpdateSingleEntity;","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Psr\\Log\\LoggerInterface;","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Psr\\Log\\LoggerInterface;","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"'entityId' => $event->getEntityId(),","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"'entityId' => $event->getEntityId(),","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"]);","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"]);","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/**","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* @important:","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* Synchronous event should eventually be deprecated.","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* Instant write operations are blocking and should be used sparingly.","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* It is much better in terms of performance to write 100 or 1000 documents at once,","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* and have one blocking reindex operation, instead of writing 10 documents synchronously.","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"*/","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"if ($event->isSyncEvent()) {","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"if ($event->isSyncEvent()) {","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$this->handleSyncEvent($event);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$this->handleSyncEvent($event);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AsyncUpdateElasticSearch::markEntityForUpdate(","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AsyncUpdateElasticSearch::markEntityForUpdate(","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getUpdateTargetValue(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getUpdateTargetValue(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getEntityId(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getEntityId(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->isPriority()","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL,","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"}]...
|
358736986986908370
|
-1127563140618445682
|
click
|
accessibility
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
Close tab
New Tab
Customize sidebar
Close Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
AI Chat settings
Close
WORK, Google Account: [EMAIL]
Main menu
New chat
Gemini
New Chat
Open menu for conversation actions.
Conversation with Gemini
Conversation with Gemini
Show the uploaded image in a lightbox
Copy prompt
You said Make a PR of changes Find potential issues and bottlenecks
You said
Make a PR of changes Find potential issues and bottlenecks
Listen
Show thinking
Gemini said
Gemini said
I can see you've uploaded a screenshot of a code diff, likely from a version control system given the red and green highlights. I would love to help you review the changes, spot bottlenecks, and help you draft a Pull Request.
However,
the image resolution is far too low for me to read.
It appears to be a completely zoomed-out view where the code has been reduced to tiny, illegible pixels. Because of this, I cannot extract any text or logic to analyze.
How You Can Share the Code
How You Can Share the Code
To help me review your code effectively, please try one of the following:
Paste the text directly:
Copy the specific code blocks (both the old and new versions if possible) and paste them directly into our chat.
Upload the files:
If the changes are extensive, you can upload the raw text or code files.
Take high-resolution screenshots:
If you must use images, take closer, readable screenshots of the specific functions or methods you want me to review.
Once you provide the readable code, I can dive right in to identify potential bugs, assess performance bottlenecks, and help you summarize the changes for your PR!
Good response
Bad response
Share & export
Copy
Show more options
Copy prompt
Edit
You said app/Component/ES/Listeners/UpdateMultipleTargetsListener.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\Component\ES\Listeners; namespace Jiminny\Component\ES\Listeners; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Contracts\ES\Events\UpdateMultipleEntities; use Jiminny\Contracts\ES\Events\UpdateMultipleEntities; use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface; AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntities(), $event->getEntities(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } } } app/Component/ES/Listeners/UpdateSingleTargetListener.php +9-1Lines changed: 9 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Actions\TrackElasticSearchOperations; use Jiminny\Component\ES\Actions\TrackElasticSearchOperations; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Contracts\ES\Events\UpdateSingleEntity; use Jiminny\Contracts\ES\Events\UpdateSingleEntity; use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface; 'entityId' => $event->getEntityId(), 'entityId' => $event->getEntityId(), ]); ]); /** * @important: * Synchronous event should eventually be deprecated. * Instant write operations are blocking and should be used sparingly. * It is much better in terms of performance to write 100 or 1000 documents at once, * and have one blocking reindex operation, instead of writing 10 documents synchronously. */ if ($event->isSyncEvent()) { if ($event->isSyncEvent()) { $this->handleSyncEvent($event); $this->handleSyncEvent($event); AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntityId(), $event->getEntityId(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } app/Component/ES/Processor/Actions/UpsertDocumentsAction.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SimpleCollection; use Jiminny\Component\ES\Processor\DTOs\SimpleCollection; use Jiminny\Component\ES\Processor\ResponseEvaluator; use Jiminny\Component\ES\Processor\ResponseEvaluator; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Exceptions\InvalidDataException; use Jiminny\Exceptions\InvalidDataException; use Sentry\Laravel\Facade as Sentry; use Sentry\Laravel\Facade as Sentry; AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( entityType: $this->updateTarget, entityType: $this->updateTarget, entityId: (int) $document->getId(), entityId: (int) $document->getId(), withPriority: true priority: QueuePriorityEnum::HIGH, ); ); } } app/Component/ES/Processor/DTOs/SelectionList.php +54-17Lines changed: 54 additions & 17 deletions Original file line numberOriginal file lineDiff line numberDiff line change namespace Jiminny\Component\ES\Processor\DTOs; namespace Jiminny\Component\ES\Processor\DTOs; use Jiminny\Component\ES\QueuePriorityEnum; /** /** * A very basic and simple collection of entity IDs. * A very basic and simple collection of entity IDs. */ */ class SelectionList class SelectionList { { public function __construct( private const int DEFAULT_CHUNK = 200; private readonly array $priorityEntityIdList = [], private readonly array $normalEntityIdList = [], private int $chunkSize = self::DEFAULT_CHUNK; private readonly bool $isStaleChunkSelected = false, private bool $isStaleChunkSelected = false; private readonly int $chunkSize = 200, private array $selectedEntityIds = []; ) { // Do nothing public function setChunkSize(int $chunkSize): void { $this->chunkSize = $chunkSize; } } public function getAllIds(): array public function markStale(): void { { return array_merge($this->priorityEntityIdList, $this->normalEntityIdList); $this->isStaleChunkSelected = true; } } public function count(): int public function addEntityList(string|QueuePriorityEnum $priority, array $entityIds): void { { return count($this->priorityEntityIdList) + count($this->normalEntityIdList); $priorityKey = $this->normalisePriority($priority); if (! array_key_exists($priorityKey, $this->selectedEntityIds)) { $this->selectedEntityIds[$priorityKey] = []; } $this->selectedEntityIds[$priorityKey] = array_merge($this->selectedEntityIds[$priorityKey], $entityIds); } } public function isEmpty(): bool /** * @return string[] */ public function getEntityListGroups(): array { { return empty($this->priorityEntityIdList) && empty($this->normalEntityIdList); return array_keys($this->selectedEntityIds); } } public function getHighPriorityEntityIds(): array public function getEntityListItemsByGroup(string|QueuePriorityEnum $priority): array { { return $this->priorityEntityIdList; $priorityKey = $this->normalisePriority($priority); return $this->selectedEntityIds[$priorityKey] ?? []; } } public function getNormalPriorityEntityId(): array public function getAllIds(): array { { return $this->normalEntityIdList; $allIds = []; foreach ($this->selectedEntityIds as $entityIds) { $allIds = array_merge($allIds, $entityIds); } return $allIds; } public function count(): int { return array_sum( array_map('count', $this->selectedEntityIds) ); } public function isEmpty(): bool { return $this->count() === 0; } } public function isStaleChunkSelected(): bool public function isStaleChunkSelected(): bool { { return $this->count() >= $this->chunkSize; return $this->count() >= $this->chunkSize; } } private function normalisePriority(string|QueuePriorityEnum $priority): string { return $priority instanceof QueuePriorityEnum ? $priority->value : $priority; } } } app/Component/ES/Processor/Traits/SelectEntityListTrait.php +27-4Lines changed: 27 additions & 4 deletions Original file line numberOriginal file lineDiff line numberDiff line change use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; /** /** * Build the correct source list name for the type of entity and priority * Build the correct source list name for the type of entity and priority */ */ trait SelectEntityListTrait trait SelectEntityListTrait { { /** * Highest priority queue for data requiring near-instant availability. * Very few entities should be added here, only when absolutely necessary. */ private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; /** * Normal priority queue for normal application operations. * Almost all update events should pass through this queue */ private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; protected static function selectTargetList(string $entityType, bool $withPriority = false): string /** { * Nonblocking low priority queue. This queue will be consumed only when there is nothing * with higher priority. * * This queue will be used for operations such as es:reset-async */ private const string ENTITIES_LOW_PRIORITIES_LIST = '%s-for-update-low'; protected static function selectTargetList( string $entityType, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { if (! in_array($entityType, UpdateTarget::allowedTargets())) { if (! in_array($entityType, UpdateTarget::allowedTargets())) { throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); } } if ($withPriority) { if ($priority->isHigh()) { Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); } } if ($priority->isLow()) { return sprintf(self::ENTITIES_LOW_PRIORITIES_LIST, $entityType); } return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); } } } } app/Component/ES/Processor/TargetEntitiesSelector.php +26-21Lines changed: 26 additions & 21 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SelectionList; use Jiminny\Component\ES\Processor\DTOs\SelectionList; use Jiminny\Component\ES\Processor\Traits\ExtractIdsTrait; use Jiminny\Component\ES\Processor\Traits\ExtractIdsTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\QueuePriorityEnum; /** /** * This class supplies a list of entities pending an update. * This class supplies a list of entities pending an update. public function select(): SelectionList public function select(): SelectionList { { $staleWorkEntityIds = $this->getStaleChunk(); $selectionList = new SelectionList(); $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $staleWorkEntityIds = $this->getStaleChunk(); if (count($staleWorkEntityIds) > 0) { if (count($staleWorkEntityIds) > 0) { return new SelectionList( /** priorityEntityIdList: $staleWorkEntityIds, * Stale chunks are treated as high priority isStaleChunkSelected: true, */ chunkSize: ChunkSize::getStaleChunkSize($this->updateTarget), $selectionList->markStale(); ); $selectionList->addEntityList(QueuePriorityEnum::HIGH, $staleWorkEntityIds); $selectionList->setChunkSize(ChunkSize::getStaleChunkSize($this->updateTarget)); return $selectionList; } } $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $selectionList->setChunkSize($mainChunkSize); $priorityEntityIdsList = $this->extractIdsFromSet( $priorityEntityIdsList = $this->extractIds(QueuePriorityEnum::HIGH, $mainChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, true), $selectionList->addEntityList(QueuePriorityEnum::HIGH, $priorityEntityIdsList); $mainChunkSize, ); $normalEntityIdsList = []; $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); if ($normalEntityChunkSize > 0) { if ($normalEntityChunkSize > 0) { $normalEntityIdsList = $this->extractIdsFromSet( $normalEntityIdsList = $this->extractIds(QueuePriorityEnum::NORMAL, $normalEntityChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, false), $selectionList->addEntityList(QueuePriorityEnum::NORMAL, $normalEntityIdsList); $normalEntityChunkSize ); } } return new SelectionList( return $selectionList; priorityEntityIdList: $priorityEntityIdsList, normalEntityIdList: $normalEntityIdsList, chunkSize: $mainChunkSize ); } } private function getStaleChunk(): array private function getStaleChunk(): array return []; return []; } } private function extractIds(QueuePriorityEnum $priority, int $chunkSize): array { return $this->extractIdsFromSet( AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, $priority), $chunkSize ); } } } app/Component/ES/AsyncUpdateElasticSearch.php +17-10Lines changed: 17 additions & 10 deletions Original file line numberOriginal file lineDiff line numberDiff line change * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * and other activity related data * and other activity related data */ */ public static function markEntityForUpdate(string $entityType, int $entityId, bool $withPriority = false): void public static function markEntityForUpdate( { string $entityType, $targetList = self::selectTargetList($entityType, $withPriority); int $entityId, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { $targetList = self::selectTargetList($entityType, $priority); Redis::sadd($targetList, $entityId); Redis::sadd($targetList, $entityId); Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ 'entityType' => $entityType, 'entityType' => $entityType, 'entityId' => $entityId, 'entityId' => $entityId, 'collectionKey' => $targetList, 'collectionKey' => $targetList, 'withPriority' => $withPriority, 'priority' => $priority->value, ]); ]); } } public static function bulkMarkEntitiesForUpdate( public static function bulkMarkEntitiesForUpdate( string $entityType, string $entityType, array $entityIds, array $entityIds, bool $withPriority = false QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { ): void { if (empty($entityIds)) { if (empty($entityIds)) { return; return; } } $targetList = self::selectTargetList($entityType, $withPriority); $targetList = self::selectTargetList($entityType, $priority); Redis::saddarray($targetList, $entityIds); Redis::saddarray($targetList, $entityIds); } } * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Takes priority into consideration. * Takes priority into consideration. */ */ public static function getEntitiesSourceList(string $updateTarget, $priority = false): string public static function getEntitiesSourceList( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { return self::selectTargetList($updateTarget, $priority); return self::selectTargetList($updateTarget, $priority); } } /** /** * Externally called helper methods * Externally called helper methods * - count and flush * - count and flush */ */ public static function getEntitiesListCount(string $updateTarget, $priority = false): int public static function getEntitiesListCount( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): int { $targetList = self::selectTargetList($updateTarget, $priority); $targetList = self::selectTargetList($updateTarget, $priority); return Redis::scard($targetList); return Redis::scard($targetList); app/Component/ES/QueuePriorityEnum.php +40Lines changed: 40 additions & 0 deletions Original file line numberOriginal file lineDiff line numberDiff line change <?php declare(strict_types=1); namespace Jiminny\Component\ES; use Jiminny\Exceptions\InvalidArgumentException; enum QueuePriorityEnum: string { case HIGH = 'high'; case NORMAL = 'normal'; case LOW = 'low'; public static function tryFromString(string $value): self { if (! self::isValid($value)) { throw new InvalidArgumentException( sprintf('Invalid queue priority "%s" selected', $value) ); } return self::tryFrom($value); } public static function isValid(string $value): bool { return self::tryFrom($value) !== null; } public function isLow(): bool { return $this === self::LOW; } public function isHigh(): bool { return $this === self::HIGH; } } app/Component/ES/UpdateProcessManager.php +12-9Lines changed: 12 additions & 9 deletions Original file line numberOriginal file lineDiff line numberDiff line change if ($selectionList->isEmpty()) { if ($selectionList->isEmpty()) { return false; return false; } } /** /** * A stale chunk will always be smaller than a regular chunk. * A stale chunk will always be smaller than a regular chunk. * That doesn't mean there aren't any other scheduled entities for processing * That doesn't mean there aren't any other scheduled entities for processing private function rescheduleThrottledEntities(SelectionList $selectionList): void private function rescheduleThrottledEntities(SelectionList $selectionList): void { { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $groups = $selectionList->getEntityListGroups(); $this->updateTarget, foreach ($groups as $eachGroup) { $selectionList->getNormalPriorityEntityId() $groupEntityIds = $selectionList->getEntityListItemsByGroup($eachGroup); ); if (! empty($groupEntityIds)) { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $this->updateTarget, entityType: $this->updateTarget, $selectionList->getHighPriorityEntityIds(), entityIds: $groupEntityIds, true priority: QueuePriorityEnum::tryFromString($eachGroup) ); ); } } } } } } app/Console/Commands/Elasticsearch/AsyncUpdateEsEntities.php +9-3Lines changed: 9 additions & 3 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Illuminate\Support\Str; use Illuminate\Support\Str; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Component\ES\UpdateProcessManager; use Jiminny\Component\ES\UpdateProcessManager; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Traits\GracefullyStoppable; use Jiminny\Traits\GracefullyStoppable; Redis::set($gaugeLockName, true); Redis::set($gaugeLockName, true); Redis::expire($gaugeLockName, 60); Redis::expire($gaugeLockName, 60); $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::HIGH), ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update', $updateTarget), stat: sprintf('jiminny.%s-for-update', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::NORMAL), ); ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), stat: sprintf('jiminny.%s-for-update-low', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, true), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::LOW), ); ); } } app/Console/Commands/Elasticsearch/ResetAsyncElasticSearchCommand.php +5-1Lines changed: 5 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\Traits\ValidateUpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\ValidateUpdateTargetTrait; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Component\ES\Repositories\EsResetRepositoryInterface; use Jiminny\Component\ES\Repositories\EsResetRepositoryInterface; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Traits\GracefullyStoppable; use Jiminny\Traits\GracefullyStoppable; private function getRemainingScheduledEntities(bool $printStatus = false): int private function getRemainingScheduledEntities(bool $printStatus = false): int { { $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget, true); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount( $this->updateTarget, QueuePriorityEnum::HIGH ); if ($printStatus) { if ($printStatus) { $this->line( $this->line(
You said
app/Component/ES/Listeners/UpdateMultipleTargetsListener.php
+2-1Lines changed: 2 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\Component\ES\Listeners;
namespace Jiminny\Component\ES\Listeners;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\QueuePriorityEnum;
use Jiminny\Contracts\ES\Events\UpdateMultipleEntities;
use Jiminny\Contracts\ES\Events\UpdateMultipleEntities;
use Psr\Log\LoggerInterface;
use Psr\Log\LoggerInterface;
AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(
AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(
$event->getUpdateTargetValue(),
$event->getUpdateTargetValue(),
$event->getEntities(),
$event->getEntities(),
$event->isPriority()
$event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL,
);
);
}
}
}
}
app/Component/ES/Listeners/UpdateSingleTargetListener.php
+9-1Lines changed: 9 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Actions\TrackElasticSearchOperations;
use Jiminny\Component\ES\Actions\TrackElasticSearchOperations;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\Processor\EntityQueryBuilder;
use Jiminny\Component\ES\Processor\EntityQueryBuilder;
use Jiminny\Component\ES\QueuePriorityEnum;
use Jiminny\Contracts\ES\Events\UpdateSingleEntity;
use Jiminny\Contracts\ES\Events\UpdateSingleEntity;
use Psr\Log\LoggerInterface;
use Psr\Log\LoggerInterface;
'entityId' => $event->getEntityId(),
'entityId' => $event->getEntityId(),
]);
]);
/**
* @important:
* Synchronous event should eventually be deprecated.
* Instant write operations are blocking and should be used sparingly.
* It is much better in terms of performance to write 100 or 1000 documents at once,
* and have one blocking reindex operation, instead of writing 10 documents synchronously.
*/
if ($event->isSyncEvent()) {
if ($event->isSyncEvent()) {
$this->handleSyncEvent($event);
$this->handleSyncEvent($event);
AsyncUpdateElasticSearch::markEntityForUpdate(
AsyncUpdateElasticSearch::markEntityForUpdate(
$event->getUpdateTargetValue(),
$event->getUpdateTargetValue(),
$event->getEntityId(),
$event->getEntityId(),
$event->isPriority()
$event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL,...
|
55695
|
NULL
|
NULL
|
NULL
|
|
55697
|
1935
|
0
|
2026-05-19T06:41:56.137806+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779172916137_m2.jpg...
|
Firefox
|
JY-20808 low priority indexing queue by Vasil-Jimi JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app — Work...
|
1
|
github.com/jiminny/app/pull/12082/changes#diff-49a github.com/jiminny/app/pull/12082/changes#diff-49a79d99c97caf7fc27ecb1dbacab5a29d871822caa0db0c71e94957c28c87af...
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
Close tab
New Tab
Customize sidebar
Close Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
AI Chat settings
Close
WORK, Google Account: [EMAIL]
Main menu
New chat
Gemini
New Chat
Open menu for conversation actions.
Conversation with Gemini
Conversation with Gemini
Show the uploaded image in a lightbox
Copy prompt
You said Make a PR of changes Find potential issues and bottlenecks
You said
Make a PR of changes Find potential issues and bottlenecks
Listen
Show thinking
Gemini said
Gemini said
I can see you've uploaded a screenshot of a code diff, likely from a version control system given the red and green highlights. I would love to help you review the changes, spot bottlenecks, and help you draft a Pull Request.
However,
the image resolution is far too low for me to read.
It appears to be a completely zoomed-out view where the code has been reduced to tiny, illegible pixels. Because of this, I cannot extract any text or logic to analyze.
How You Can Share the Code
How You Can Share the Code
To help me review your code effectively, please try one of the following:
Paste the text directly:
Copy the specific code blocks (both the old and new versions if possible) and paste them directly into our chat.
Upload the files:
If the changes are extensive, you can upload the raw text or code files.
Take high-resolution screenshots:
If you must use images, take closer, readable screenshots of the specific functions or methods you want me to review.
Once you provide the readable code, I can dive right in to identify potential bugs, assess performance bottlenecks, and help you summarize the changes for your PR!
Good response
Bad response
Share & export
Copy
Show more options
Copy prompt
Edit
You said app/Component/ES/Listeners/UpdateMultipleTargetsListener.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\Component\ES\Listeners; namespace Jiminny\Component\ES\Listeners; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Contracts\ES\Events\UpdateMultipleEntities; use Jiminny\Contracts\ES\Events\UpdateMultipleEntities; use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface; AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntities(), $event->getEntities(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } } } app/Component/ES/Listeners/UpdateSingleTargetListener.php +9-1Lines changed: 9 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Actions\TrackElasticSearchOperations; use Jiminny\Component\ES\Actions\TrackElasticSearchOperations; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Contracts\ES\Events\UpdateSingleEntity; use Jiminny\Contracts\ES\Events\UpdateSingleEntity; use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface; 'entityId' => $event->getEntityId(), 'entityId' => $event->getEntityId(), ]); ]); /** * @important: * Synchronous event should eventually be deprecated. * Instant write operations are blocking and should be used sparingly. * It is much better in terms of performance to write 100 or 1000 documents at once, * and have one blocking reindex operation, instead of writing 10 documents synchronously. */ if ($event->isSyncEvent()) { if ($event->isSyncEvent()) { $this->handleSyncEvent($event); $this->handleSyncEvent($event); AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntityId(), $event->getEntityId(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } app/Component/ES/Processor/Actions/UpsertDocumentsAction.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SimpleCollection; use Jiminny\Component\ES\Processor\DTOs\SimpleCollection; use Jiminny\Component\ES\Processor\ResponseEvaluator; use Jiminny\Component\ES\Processor\ResponseEvaluator; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Exceptions\InvalidDataException; use Jiminny\Exceptions\InvalidDataException; use Sentry\Laravel\Facade as Sentry; use Sentry\Laravel\Facade as Sentry; AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( entityType: $this->updateTarget, entityType: $this->updateTarget, entityId: (int) $document->getId(), entityId: (int) $document->getId(), withPriority: true priority: QueuePriorityEnum::HIGH, ); ); } } app/Component/ES/Processor/DTOs/SelectionList.php +54-17Lines changed: 54 additions & 17 deletions Original file line numberOriginal file lineDiff line numberDiff line change namespace Jiminny\Component\ES\Processor\DTOs; namespace Jiminny\Component\ES\Processor\DTOs; use Jiminny\Component\ES\QueuePriorityEnum; /** /** * A very basic and simple collection of entity IDs. * A very basic and simple collection of entity IDs. */ */ class SelectionList class SelectionList { { public function __construct( private const int DEFAULT_CHUNK = 200; private readonly array $priorityEntityIdList = [], private readonly array $normalEntityIdList = [], private int $chunkSize = self::DEFAULT_CHUNK; private readonly bool $isStaleChunkSelected = false, private bool $isStaleChunkSelected = false; private readonly int $chunkSize = 200, private array $selectedEntityIds = []; ) { // Do nothing public function setChunkSize(int $chunkSize): void { $this->chunkSize = $chunkSize; } } public function getAllIds(): array public function markStale(): void { { return array_merge($this->priorityEntityIdList, $this->normalEntityIdList); $this->isStaleChunkSelected = true; } } public function count(): int public function addEntityList(string|QueuePriorityEnum $priority, array $entityIds): void { { return count($this->priorityEntityIdList) + count($this->normalEntityIdList); $priorityKey = $this->normalisePriority($priority); if (! array_key_exists($priorityKey, $this->selectedEntityIds)) { $this->selectedEntityIds[$priorityKey] = []; } $this->selectedEntityIds[$priorityKey] = array_merge($this->selectedEntityIds[$priorityKey], $entityIds); } } public function isEmpty(): bool /** * @return string[] */ public function getEntityListGroups(): array { { return empty($this->priorityEntityIdList) && empty($this->normalEntityIdList); return array_keys($this->selectedEntityIds); } } public function getHighPriorityEntityIds(): array public function getEntityListItemsByGroup(string|QueuePriorityEnum $priority): array { { return $this->priorityEntityIdList; $priorityKey = $this->normalisePriority($priority); return $this->selectedEntityIds[$priorityKey] ?? []; } } public function getNormalPriorityEntityId(): array public function getAllIds(): array { { return $this->normalEntityIdList; $allIds = []; foreach ($this->selectedEntityIds as $entityIds) { $allIds = array_merge($allIds, $entityIds); } return $allIds; } public function count(): int { return array_sum( array_map('count', $this->selectedEntityIds) ); } public function isEmpty(): bool { return $this->count() === 0; } } public function isStaleChunkSelected(): bool public function isStaleChunkSelected(): bool { { return $this->count() >= $this->chunkSize; return $this->count() >= $this->chunkSize; } } private function normalisePriority(string|QueuePriorityEnum $priority): string { return $priority instanceof QueuePriorityEnum ? $priority->value : $priority; } } } app/Component/ES/Processor/Traits/SelectEntityListTrait.php +27-4Lines changed: 27 additions & 4 deletions Original file line numberOriginal file lineDiff line numberDiff line change use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; /** /** * Build the correct source list name for the type of entity and priority * Build the correct source list name for the type of entity and priority */ */ trait SelectEntityListTrait trait SelectEntityListTrait { { /** * Highest priority queue for data requiring near-instant availability. * Very few entities should be added here, only when absolutely necessary. */ private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; /** * Normal priority queue for normal application operations. * Almost all update events should pass through this queue */ private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; protected static function selectTargetList(string $entityType, bool $withPriority = false): string /** { * Nonblocking low priority queue. This queue will be consumed only when there is nothing * with higher priority. * * This queue will be used for operations such as es:reset-async */ private const string ENTITIES_LOW_PRIORITIES_LIST = '%s-for-update-low'; protected static function selectTargetList( string $entityType, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { if (! in_array($entityType, UpdateTarget::allowedTargets())) { if (! in_array($entityType, UpdateTarget::allowedTargets())) { throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); } } if ($withPriority) { if ($priority->isHigh()) { Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); } } if ($priority->isLow()) { return sprintf(self::ENTITIES_LOW_PRIORITIES_LIST, $entityType); } return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); } } } } app/Component/ES/Processor/TargetEntitiesSelector.php +26-21Lines changed: 26 additions & 21 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SelectionList; use Jiminny\Component\ES\Processor\DTOs\SelectionList; use Jiminny\Component\ES\Processor\Traits\ExtractIdsTrait; use Jiminny\Component\ES\Processor\Traits\ExtractIdsTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\QueuePriorityEnum; /** /** * This class supplies a list of entities pending an update. * This class supplies a list of entities pending an update. public function select(): SelectionList public function select(): SelectionList { { $staleWorkEntityIds = $this->getStaleChunk(); $selectionList = new SelectionList(); $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $staleWorkEntityIds = $this->getStaleChunk(); if (count($staleWorkEntityIds) > 0) { if (count($staleWorkEntityIds) > 0) { return new SelectionList( /** priorityEntityIdList: $staleWorkEntityIds, * Stale chunks are treated as high priority isStaleChunkSelected: true, */ chunkSize: ChunkSize::getStaleChunkSize($this->updateTarget), $selectionList->markStale(); ); $selectionList->addEntityList(QueuePriorityEnum::HIGH, $staleWorkEntityIds); $selectionList->setChunkSize(ChunkSize::getStaleChunkSize($this->updateTarget)); return $selectionList; } } $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $selectionList->setChunkSize($mainChunkSize); $priorityEntityIdsList = $this->extractIdsFromSet( $priorityEntityIdsList = $this->extractIds(QueuePriorityEnum::HIGH, $mainChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, true), $selectionList->addEntityList(QueuePriorityEnum::HIGH, $priorityEntityIdsList); $mainChunkSize, ); $normalEntityIdsList = []; $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); if ($normalEntityChunkSize > 0) { if ($normalEntityChunkSize > 0) { $normalEntityIdsList = $this->extractIdsFromSet( $normalEntityIdsList = $this->extractIds(QueuePriorityEnum::NORMAL, $normalEntityChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, false), $selectionList->addEntityList(QueuePriorityEnum::NORMAL, $normalEntityIdsList); $normalEntityChunkSize ); } } return new SelectionList( return $selectionList; priorityEntityIdList: $priorityEntityIdsList, normalEntityIdList: $normalEntityIdsList, chunkSize: $mainChunkSize ); } } private function getStaleChunk(): array private function getStaleChunk(): array return []; return []; } } private function extractIds(QueuePriorityEnum $priority, int $chunkSize): array { return $this->extractIdsFromSet( AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, $priority), $chunkSize ); } } } app/Component/ES/AsyncUpdateElasticSearch.php +17-10Lines changed: 17 additions & 10 deletions Original file line numberOriginal file lineDiff line numberDiff line change * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * and other activity related data * and other activity related data */ */ public static function markEntityForUpdate(string $entityType, int $entityId, bool $withPriority = false): void public static function markEntityForUpdate( { string $entityType, $targetList = self::selectTargetList($entityType, $withPriority); int $entityId, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { $targetList = self::selectTargetList($entityType, $priority); Redis::sadd($targetList, $entityId); Redis::sadd($targetList, $entityId); Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ 'entityType' => $entityType, 'entityType' => $entityType, 'entityId' => $entityId, 'entityId' => $entityId, 'collectionKey' => $targetList, 'collectionKey' => $targetList, 'withPriority' => $withPriority, 'priority' => $priority->value, ]); ]); } } public static function bulkMarkEntitiesForUpdate( public static function bulkMarkEntitiesForUpdate( string $entityType, string $entityType, array $entityIds, array $entityIds, bool $withPriority = false QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { ): void { if (empty($entityIds)) { if (empty($entityIds)) { return; return; } } $targetList = self::selectTargetList($entityType, $withPriority); $targetList = self::selectTargetList($entityType, $priority); Redis::saddarray($targetList, $entityIds); Redis::saddarray($targetList, $entityIds); } } * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Takes priority into consideration. * Takes priority into consideration. */ */ public static function getEntitiesSourceList(string $updateTarget, $priority = false): string public static function getEntitiesSourceList( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { return self::selectTargetList($updateTarget, $priority); return self::selectTargetList($updateTarget, $priority); } } /** /** * Externally called helper methods * Externally called helper methods * - count and flush * - count and flush */ */ public static function getEntitiesListCount(string $updateTarget, $priority = false): int public static function getEntitiesListCount( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): int { $targetList = self::selectTargetList($updateTarget, $priority); $targetList = self::selectTargetList($updateTarget, $priority); return Redis::scard($targetList); return Redis::scard($targetList); app/Component/ES/QueuePriorityEnum.php +40Lines changed: 40 additions & 0 deletions Original file line numberOriginal file lineDiff line numberDiff line change <?php declare(strict_types=1); namespace Jiminny\Component\ES; use Jiminny\Exceptions\InvalidArgumentException; enum QueuePriorityEnum: string { case HIGH = 'high'; case NORMAL = 'normal'; case LOW = 'low'; public static function tryFromString(string $value): self { if (! self::isValid($value)) { throw new InvalidArgumentException( sprintf('Invalid queue priority "%s" selected', $value) ); } return self::tryFrom($value); } public static function isValid(string $value): bool { return self::tryFrom($value) !== null; } public function isLow(): bool { return $this === self::LOW; } public function isHigh(): bool { return $this === self::HIGH; } } app/Component/ES/UpdateProcessManager.php +12-9Lines changed: 12 additions & 9 deletions Original file line numberOriginal file lineDiff line numberDiff line change if ($selectionList->isEmpty()) { if ($selectionList->isEmpty()) { return false; return false; } } /** /** * A stale chunk will always be smaller than a regular chunk. * A stale chunk will always be smaller than a regular chunk. * That doesn't mean there aren't any other scheduled entities for processing * That doesn't mean there aren't any other scheduled entities for processing private function rescheduleThrottledEntities(SelectionList $selectionList): void private function rescheduleThrottledEntities(SelectionList $selectionList): void { { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $groups = $selectionList->getEntityListGroups(); $this->updateTarget, foreach ($groups as $eachGroup) { $selectionList->getNormalPriorityEntityId() $groupEntityIds = $selectionList->getEntityListItemsByGroup($eachGroup); ); if (! empty($groupEntityIds)) { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $this->updateTarget, entityType: $this->updateTarget, $selectionList->getHighPriorityEntityIds(), entityIds: $groupEntityIds, true priority: QueuePriorityEnum::tryFromString($eachGroup) ); ); } } } } } } app/Console/Commands/Elasticsearch/AsyncUpdateEsEntities.php +9-3Lines changed: 9 additions & 3 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Illuminate\Support\Str; use Illuminate\Support\Str; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Component\ES\UpdateProcessManager; use Jiminny\Component\ES\UpdateProcessManager; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Traits\GracefullyStoppable; use Jiminny\Traits\GracefullyStoppable; Redis::set($gaugeLockName, true); Redis::set($gaugeLockName, true); Redis::expire($gaugeLockName, 60); Redis::expire($gaugeLockName, 60); $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::HIGH), ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update', $updateTarget), stat: sprintf('jiminny.%s-for-update', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::NORMAL), ); ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), stat: sprintf('jiminny.%s-for-update-low', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, true), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::LOW), ); ); } } app/Console/Commands/Elasticsearch/ResetAsyncElasticSearchCommand.php +5-1Lines changed: 5 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\Traits\ValidateUpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\ValidateUpdateTargetTrait; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Component\ES\Repositories\EsResetRepositoryInterface; use Jiminny\Component\ES\Repositories\EsResetRepositoryInterface; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Traits\GracefullyStoppable; use Jiminny\Traits\GracefullyStoppable; private function getRemainingScheduledEntities(bool $printStatus = false): int private function getRemainingScheduledEntities(bool $printStatus = false): int { { $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget, true); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount( $this->updateTarget, QueuePriorityEnum::HIGH ); if ($printStatus) { if ($printStatus) { $this->line( $this->line(
You said
app/Component/ES/Listeners/UpdateMultipleTargetsListener.php
+2-1Lines changed: 2 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\Component\ES\Listeners;
namespace Jiminny\Component\ES\Listeners;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\QueuePriorityEnum;
use Jiminny\Contracts\ES\Events\UpdateMultipleEntities;
use Jiminny\Contracts\ES\Events\UpdateMultipleEntities;
use Psr\Log\LoggerInterface;
use Psr\Log\LoggerInterface;
AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(
AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(
$event->getUpdateTargetValue(),
$event->getUpdateTargetValue(),
$event->getEntities(),
$event->getEntities(),
$event->isPriority()
$event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL,
);
);
}
}
}
}
app/Component/ES/Listeners/UpdateSingleTargetListener.php
+9-1Lines changed: 9 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Actions\TrackElasticSearchOperations;
use Jiminny\Component\ES\Actions\TrackElasticSearchOperations;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\Processor\EntityQueryBuilder;
use Jiminny\Component\ES\Processor\EntityQueryBuilder;
use Jiminny\Component\ES\QueuePriorityEnum;
use Jiminny\Contracts\ES\Events\UpdateSingleEntity;
use Jiminny\Contracts\ES\Events\UpdateSingleEntity;
use Psr\Log\LoggerInterface;
use Psr\Log\LoggerInterface;
'entityId' => $event->getEntityId(),
'entityId' => $event->getEntityId(),
]);
]);
/**
* @important:
* Synchronous event should eventually be deprecated.
* Instant write operations are blocking and should be used sparingly.
* It is much better in terms of performance to write 100 or 1000 documents at once,
* and have one blocking reindex operation, instead of writing 10 documents synchronously.
*/
if ($event->isSyncEvent()) {
if ($event->isSyncEvent()) {
$this->handleSyncEvent($event);
$this->handleSyncEvent($event);
AsyncUpdateElasticSearch::markEntityForUpdate(
AsyncUpdateElasticSearch::markEntityForUpdate(
$event->getUpdateTargetValue(),
$event->getUpdateTargetValue(),
$event->getEntityId(),
$event->getEntityId(),
$event->isPriority()
$event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL,
);
);
}
}
app/Component/ES/Processor/Actions/UpsertDocumentsAction.php
+2-1Lines changed: 2 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SimpleCollection;
use Jiminny\Component\ES\Processor\DTOs\SimpleCollection;
use Jiminny\Component\ES\Processor\ResponseEvaluator;
use Jiminny\Component\ES\Processor\ResponseEvaluator;
use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait;
use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait;...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira","depth":4,"bounds":{"left":0.0,"top":0.0518755,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.06304868,"width":0.10106383,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app","depth":4,"bounds":{"left":0.0,"top":0.08459697,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app","depth":5,"bounds":{"left":0.013297873,"top":0.09577015,"width":0.18816489,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app","depth":4,"bounds":{"left":0.0,"top":0.11731844,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app","depth":5,"bounds":{"left":0.013297873,"top":0.12849163,"width":0.15674867,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.06732048,"top":0.1245012,"width":0.007978723,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New Tab","depth":4,"bounds":{"left":0.0028257978,"top":0.15163608,"width":0.07413564,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"bounds":{"left":0.0028257978,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Close Google Gemini (⌃X)","depth":6,"bounds":{"left":0.013796543,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Tabs from other devices","depth":6,"bounds":{"left":0.024933511,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"bounds":{"left":0.036070477,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"bounds":{"left":0.04720745,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"AI Chat settings","depth":7,"bounds":{"left":0.35854387,"top":0.055067837,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Close","depth":7,"bounds":{"left":0.37051198,"top":0.055067837,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"WORK, Google Account: lukas.kovalik@jiminny.com","depth":12,"bounds":{"left":0.3678524,"top":0.103751,"width":0.013297873,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Main menu","depth":12,"bounds":{"left":0.08494016,"top":0.103751,"width":0.013297873,"height":0.031923383},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New chat","depth":12,"bounds":{"left":0.09823803,"top":0.10454908,"width":0.028590426,"height":0.030327214},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Gemini","depth":15,"bounds":{"left":0.1008976,"top":0.10973663,"width":0.021941489,"height":0.020351157},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"New Chat","depth":12,"bounds":{"left":0.33992687,"top":0.103751,"width":0.013297873,"height":0.031923383},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Open menu for conversation actions.","depth":12,"bounds":{"left":0.35322472,"top":0.103751,"width":0.013297873,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXHeading","text":"Conversation with Gemini","depth":15,"bounds":{"left":0.079288565,"top":0.14764565,"width":0.0003324468,"height":0.0007980846},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Conversation with Gemini","depth":16,"bounds":{"left":0.079288565,"top":0.15003991,"width":0.1200133,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Show the uploaded image in a lightbox","depth":21,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy prompt","depth":21,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"You said Make a PR of changes Find potential issues and bottlenecks","depth":21,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"You said","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Make a PR of changes Find potential issues and bottlenecks","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Listen","depth":22,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Show thinking","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Gemini said","depth":20,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Gemini said","depth":21,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"I can see you've uploaded a screenshot of a code diff, likely from a version control system given the red and green highlights. I would love to help you review the changes, spot bottlenecks, and help you draft a Pull Request.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"However,","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"the image resolution is far too low for me to read.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"It appears to be a completely zoomed-out view where the code has been reduced to tiny, illegible pixels. Because of this, I cannot extract any text or logic to analyze.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"How You Can Share the Code","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"How You Can Share the Code","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"To help me review your code effectively, please try one of the following:","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Paste the text directly:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Copy the specific code blocks (both the old and new versions if possible) and paste them directly into our chat.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Upload the files:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"If the changes are extensive, you can upload the raw text or code files.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Take high-resolution screenshots:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"If you must use images, take closer, readable screenshots of the specific functions or methods you want me to review.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Once you provide the readable code, I can dive right in to identify potential bugs, assess performance bottlenecks, and help you summarize the changes for your PR!","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Good response","depth":22,"on_screen":false,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Bad response","depth":22,"on_screen":false,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Share & export","depth":21,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy","depth":22,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Show more options","depth":21,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy prompt","depth":21,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Edit","depth":21,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"You said app/Component/ES/Listeners/UpdateMultipleTargetsListener.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\\Component\\ES\\Listeners; namespace Jiminny\\Component\\ES\\Listeners; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Contracts\\ES\\Events\\UpdateMultipleEntities; use Jiminny\\Contracts\\ES\\Events\\UpdateMultipleEntities; use Psr\\Log\\LoggerInterface; use Psr\\Log\\LoggerInterface; AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntities(), $event->getEntities(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } } } app/Component/ES/Listeners/UpdateSingleTargetListener.php +9-1Lines changed: 9 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Actions\\TrackElasticSearchOperations; use Jiminny\\Component\\ES\\Actions\\TrackElasticSearchOperations; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder; use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Contracts\\ES\\Events\\UpdateSingleEntity; use Jiminny\\Contracts\\ES\\Events\\UpdateSingleEntity; use Psr\\Log\\LoggerInterface; use Psr\\Log\\LoggerInterface; 'entityId' => $event->getEntityId(), 'entityId' => $event->getEntityId(), ]); ]); /** * @important: * Synchronous event should eventually be deprecated. * Instant write operations are blocking and should be used sparingly. * It is much better in terms of performance to write 100 or 1000 documents at once, * and have one blocking reindex operation, instead of writing 10 documents synchronously. */ if ($event->isSyncEvent()) { if ($event->isSyncEvent()) { $this->handleSyncEvent($event); $this->handleSyncEvent($event); AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntityId(), $event->getEntityId(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } app/Component/ES/Processor/Actions/UpsertDocumentsAction.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Processor\\DTOs\\SimpleCollection; use Jiminny\\Component\\ES\\Processor\\DTOs\\SimpleCollection; use Jiminny\\Component\\ES\\Processor\\ResponseEvaluator; use Jiminny\\Component\\ES\\Processor\\ResponseEvaluator; use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait; use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Exceptions\\InvalidDataException; use Jiminny\\Exceptions\\InvalidDataException; use Sentry\\Laravel\\Facade as Sentry; use Sentry\\Laravel\\Facade as Sentry; AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( entityType: $this->updateTarget, entityType: $this->updateTarget, entityId: (int) $document->getId(), entityId: (int) $document->getId(), withPriority: true priority: QueuePriorityEnum::HIGH, ); ); } } app/Component/ES/Processor/DTOs/SelectionList.php +54-17Lines changed: 54 additions & 17 deletions Original file line numberOriginal file lineDiff line numberDiff line change namespace Jiminny\\Component\\ES\\Processor\\DTOs; namespace Jiminny\\Component\\ES\\Processor\\DTOs; use Jiminny\\Component\\ES\\QueuePriorityEnum; /** /** * A very basic and simple collection of entity IDs. * A very basic and simple collection of entity IDs. */ */ class SelectionList class SelectionList { { public function __construct( private const int DEFAULT_CHUNK = 200; private readonly array $priorityEntityIdList = [], private readonly array $normalEntityIdList = [], private int $chunkSize = self::DEFAULT_CHUNK; private readonly bool $isStaleChunkSelected = false, private bool $isStaleChunkSelected = false; private readonly int $chunkSize = 200, private array $selectedEntityIds = []; ) { // Do nothing public function setChunkSize(int $chunkSize): void { $this->chunkSize = $chunkSize; } } public function getAllIds(): array public function markStale(): void { { return array_merge($this->priorityEntityIdList, $this->normalEntityIdList); $this->isStaleChunkSelected = true; } } public function count(): int public function addEntityList(string|QueuePriorityEnum $priority, array $entityIds): void { { return count($this->priorityEntityIdList) + count($this->normalEntityIdList); $priorityKey = $this->normalisePriority($priority); if (! array_key_exists($priorityKey, $this->selectedEntityIds)) { $this->selectedEntityIds[$priorityKey] = []; } $this->selectedEntityIds[$priorityKey] = array_merge($this->selectedEntityIds[$priorityKey], $entityIds); } } public function isEmpty(): bool /** * @return string[] */ public function getEntityListGroups(): array { { return empty($this->priorityEntityIdList) && empty($this->normalEntityIdList); return array_keys($this->selectedEntityIds); } } public function getHighPriorityEntityIds(): array public function getEntityListItemsByGroup(string|QueuePriorityEnum $priority): array { { return $this->priorityEntityIdList; $priorityKey = $this->normalisePriority($priority); return $this->selectedEntityIds[$priorityKey] ?? []; } } public function getNormalPriorityEntityId(): array public function getAllIds(): array { { return $this->normalEntityIdList; $allIds = []; foreach ($this->selectedEntityIds as $entityIds) { $allIds = array_merge($allIds, $entityIds); } return $allIds; } public function count(): int { return array_sum( array_map('count', $this->selectedEntityIds) ); } public function isEmpty(): bool { return $this->count() === 0; } } public function isStaleChunkSelected(): bool public function isStaleChunkSelected(): bool { { return $this->count() >= $this->chunkSize; return $this->count() >= $this->chunkSize; } } private function normalisePriority(string|QueuePriorityEnum $priority): string { return $priority instanceof QueuePriorityEnum ? $priority->value : $priority; } } } app/Component/ES/Processor/Traits/SelectEntityListTrait.php +27-4Lines changed: 27 additions & 4 deletions Original file line numberOriginal file lineDiff line numberDiff line change use Illuminate\\Support\\Facades\\Log; use Illuminate\\Support\\Facades\\Log; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Exceptions\\InvalidArgumentException; use Jiminny\\Exceptions\\InvalidArgumentException; /** /** * Build the correct source list name for the type of entity and priority * Build the correct source list name for the type of entity and priority */ */ trait SelectEntityListTrait trait SelectEntityListTrait { { /** * Highest priority queue for data requiring near-instant availability. * Very few entities should be added here, only when absolutely necessary. */ private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; /** * Normal priority queue for normal application operations. * Almost all update events should pass through this queue */ private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; protected static function selectTargetList(string $entityType, bool $withPriority = false): string /** { * Nonblocking low priority queue. This queue will be consumed only when there is nothing * with higher priority. * * This queue will be used for operations such as es:reset-async */ private const string ENTITIES_LOW_PRIORITIES_LIST = '%s-for-update-low'; protected static function selectTargetList( string $entityType, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { if (! in_array($entityType, UpdateTarget::allowedTargets())) { if (! in_array($entityType, UpdateTarget::allowedTargets())) { throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); } } if ($withPriority) { if ($priority->isHigh()) { Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); } } if ($priority->isLow()) { return sprintf(self::ENTITIES_LOW_PRIORITIES_LIST, $entityType); } return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); } } } } app/Component/ES/Processor/TargetEntitiesSelector.php +26-21Lines changed: 26 additions & 21 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Processor\\DTOs\\SelectionList; use Jiminny\\Component\\ES\\Processor\\DTOs\\SelectionList; use Jiminny\\Component\\ES\\Processor\\Traits\\ExtractIdsTrait; use Jiminny\\Component\\ES\\Processor\\Traits\\ExtractIdsTrait; use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait; use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait; use Jiminny\\Component\\ES\\QueuePriorityEnum; /** /** * This class supplies a list of entities pending an update. * This class supplies a list of entities pending an update. public function select(): SelectionList public function select(): SelectionList { { $staleWorkEntityIds = $this->getStaleChunk(); $selectionList = new SelectionList(); $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $staleWorkEntityIds = $this->getStaleChunk(); if (count($staleWorkEntityIds) > 0) { if (count($staleWorkEntityIds) > 0) { return new SelectionList( /** priorityEntityIdList: $staleWorkEntityIds, * Stale chunks are treated as high priority isStaleChunkSelected: true, */ chunkSize: ChunkSize::getStaleChunkSize($this->updateTarget), $selectionList->markStale(); ); $selectionList->addEntityList(QueuePriorityEnum::HIGH, $staleWorkEntityIds); $selectionList->setChunkSize(ChunkSize::getStaleChunkSize($this->updateTarget)); return $selectionList; } } $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $selectionList->setChunkSize($mainChunkSize); $priorityEntityIdsList = $this->extractIdsFromSet( $priorityEntityIdsList = $this->extractIds(QueuePriorityEnum::HIGH, $mainChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, true), $selectionList->addEntityList(QueuePriorityEnum::HIGH, $priorityEntityIdsList); $mainChunkSize, ); $normalEntityIdsList = []; $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); if ($normalEntityChunkSize > 0) { if ($normalEntityChunkSize > 0) { $normalEntityIdsList = $this->extractIdsFromSet( $normalEntityIdsList = $this->extractIds(QueuePriorityEnum::NORMAL, $normalEntityChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, false), $selectionList->addEntityList(QueuePriorityEnum::NORMAL, $normalEntityIdsList); $normalEntityChunkSize ); } } return new SelectionList( return $selectionList; priorityEntityIdList: $priorityEntityIdsList, normalEntityIdList: $normalEntityIdsList, chunkSize: $mainChunkSize ); } } private function getStaleChunk(): array private function getStaleChunk(): array return []; return []; } } private function extractIds(QueuePriorityEnum $priority, int $chunkSize): array { return $this->extractIdsFromSet( AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, $priority), $chunkSize ); } } } app/Component/ES/AsyncUpdateElasticSearch.php +17-10Lines changed: 17 additions & 10 deletions Original file line numberOriginal file lineDiff line numberDiff line change * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * and other activity related data * and other activity related data */ */ public static function markEntityForUpdate(string $entityType, int $entityId, bool $withPriority = false): void public static function markEntityForUpdate( { string $entityType, $targetList = self::selectTargetList($entityType, $withPriority); int $entityId, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { $targetList = self::selectTargetList($entityType, $priority); Redis::sadd($targetList, $entityId); Redis::sadd($targetList, $entityId); Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ 'entityType' => $entityType, 'entityType' => $entityType, 'entityId' => $entityId, 'entityId' => $entityId, 'collectionKey' => $targetList, 'collectionKey' => $targetList, 'withPriority' => $withPriority, 'priority' => $priority->value, ]); ]); } } public static function bulkMarkEntitiesForUpdate( public static function bulkMarkEntitiesForUpdate( string $entityType, string $entityType, array $entityIds, array $entityIds, bool $withPriority = false QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { ): void { if (empty($entityIds)) { if (empty($entityIds)) { return; return; } } $targetList = self::selectTargetList($entityType, $withPriority); $targetList = self::selectTargetList($entityType, $priority); Redis::saddarray($targetList, $entityIds); Redis::saddarray($targetList, $entityIds); } } * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Takes priority into consideration. * Takes priority into consideration. */ */ public static function getEntitiesSourceList(string $updateTarget, $priority = false): string public static function getEntitiesSourceList( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { return self::selectTargetList($updateTarget, $priority); return self::selectTargetList($updateTarget, $priority); } } /** /** * Externally called helper methods * Externally called helper methods * - count and flush * - count and flush */ */ public static function getEntitiesListCount(string $updateTarget, $priority = false): int public static function getEntitiesListCount( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): int { $targetList = self::selectTargetList($updateTarget, $priority); $targetList = self::selectTargetList($updateTarget, $priority); return Redis::scard($targetList); return Redis::scard($targetList); app/Component/ES/QueuePriorityEnum.php +40Lines changed: 40 additions & 0 deletions Original file line numberOriginal file lineDiff line numberDiff line change <?php declare(strict_types=1); namespace Jiminny\\Component\\ES; use Jiminny\\Exceptions\\InvalidArgumentException; enum QueuePriorityEnum: string { case HIGH = 'high'; case NORMAL = 'normal'; case LOW = 'low'; public static function tryFromString(string $value): self { if (! self::isValid($value)) { throw new InvalidArgumentException( sprintf('Invalid queue priority \"%s\" selected', $value) ); } return self::tryFrom($value); } public static function isValid(string $value): bool { return self::tryFrom($value) !== null; } public function isLow(): bool { return $this === self::LOW; } public function isHigh(): bool { return $this === self::HIGH; } } app/Component/ES/UpdateProcessManager.php +12-9Lines changed: 12 additions & 9 deletions Original file line numberOriginal file lineDiff line numberDiff line change if ($selectionList->isEmpty()) { if ($selectionList->isEmpty()) { return false; return false; } } /** /** * A stale chunk will always be smaller than a regular chunk. * A stale chunk will always be smaller than a regular chunk. * That doesn't mean there aren't any other scheduled entities for processing * That doesn't mean there aren't any other scheduled entities for processing private function rescheduleThrottledEntities(SelectionList $selectionList): void private function rescheduleThrottledEntities(SelectionList $selectionList): void { { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $groups = $selectionList->getEntityListGroups(); $this->updateTarget, foreach ($groups as $eachGroup) { $selectionList->getNormalPriorityEntityId() $groupEntityIds = $selectionList->getEntityListItemsByGroup($eachGroup); ); if (! empty($groupEntityIds)) { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $this->updateTarget, entityType: $this->updateTarget, $selectionList->getHighPriorityEntityIds(), entityIds: $groupEntityIds, true priority: QueuePriorityEnum::tryFromString($eachGroup) ); ); } } } } } } app/Console/Commands/Elasticsearch/AsyncUpdateEsEntities.php +9-3Lines changed: 9 additions & 3 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Illuminate\\Support\\Str; use Illuminate\\Support\\Str; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Component\\ES\\UpdateProcessManager; use Jiminny\\Component\\ES\\UpdateProcessManager; use Jiminny\\Exceptions\\InvalidArgumentException; use Jiminny\\Exceptions\\InvalidArgumentException; use Jiminny\\Traits\\GracefullyStoppable; use Jiminny\\Traits\\GracefullyStoppable; Redis::set($gaugeLockName, true); Redis::set($gaugeLockName, true); Redis::expire($gaugeLockName, 60); Redis::expire($gaugeLockName, 60); $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::HIGH), ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update', $updateTarget), stat: sprintf('jiminny.%s-for-update', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::NORMAL), ); ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), stat: sprintf('jiminny.%s-for-update-low', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, true), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::LOW), ); ); } } app/Console/Commands/Elasticsearch/ResetAsyncElasticSearchCommand.php +5-1Lines changed: 5 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder; use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder; use Jiminny\\Component\\ES\\Processor\\Traits\\ValidateUpdateTargetTrait; use Jiminny\\Component\\ES\\Processor\\Traits\\ValidateUpdateTargetTrait; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Component\\ES\\Repositories\\EsResetRepositoryInterface; use Jiminny\\Component\\ES\\Repositories\\EsResetRepositoryInterface; use Jiminny\\Exceptions\\InvalidArgumentException; use Jiminny\\Exceptions\\InvalidArgumentException; use Jiminny\\Traits\\GracefullyStoppable; use Jiminny\\Traits\\GracefullyStoppable; private function getRemainingScheduledEntities(bool $printStatus = false): int private function getRemainingScheduledEntities(bool $printStatus = false): int { { $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget, true); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount( $this->updateTarget, QueuePriorityEnum::HIGH ); if ($printStatus) { if ($printStatus) { $this->line( $this->line(","depth":21,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"You said","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app/Component/ES/Listeners/UpdateMultipleTargetsListener.php","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"+2-1Lines changed: 2 additions & 1 deletion","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\\Component\\ES\\Listeners;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"namespace Jiminny\\Component\\ES\\Listeners;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\QueuePriorityEnum;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Contracts\\ES\\Events\\UpdateMultipleEntities;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Contracts\\ES\\Events\\UpdateMultipleEntities;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Psr\\Log\\LoggerInterface;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Psr\\Log\\LoggerInterface;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getUpdateTargetValue(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getUpdateTargetValue(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getEntities(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getEntities(),","depth":23,"bounds":{"left":0.20578457,"top":0.0,"width":0.052526597,"height":0.016360734},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->isPriority()","depth":23,"bounds":{"left":0.20578457,"top":0.0,"width":0.046708778,"height":0.016360734},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL,","depth":23,"bounds":{"left":0.20578457,"top":0.0,"width":0.11702128,"height":0.035514764},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":");","depth":23,"bounds":{"left":0.20578457,"top":0.0,"width":0.0033244682,"height":0.016360734},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":");","depth":23,"bounds":{"left":0.20578457,"top":0.003990423,"width":0.0033244682,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"bounds":{"left":0.20578457,"top":0.023144454,"width":0.0019946808,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"bounds":{"left":0.20578457,"top":0.042298485,"width":0.0019946808,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"bounds":{"left":0.20578457,"top":0.061452515,"width":0.0019946808,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"bounds":{"left":0.20578457,"top":0.08060654,"width":0.0019946808,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app/Component/ES/Listeners/UpdateSingleTargetListener.php","depth":23,"bounds":{"left":0.20578457,"top":0.09976058,"width":0.07762633,"height":0.035514764},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"+9-1Lines changed: 9 additions & 1 deletion","depth":23,"bounds":{"left":0.20578457,"top":0.15722266,"width":0.104222074,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Actions\\TrackElasticSearchOperations;","depth":23,"bounds":{"left":0.20578457,"top":0.19553073,"width":0.13480718,"height":0.073822826},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Actions\\TrackElasticSearchOperations;","depth":23,"bounds":{"left":0.20578457,"top":0.27214685,"width":0.13480718,"height":0.054668795},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch;","depth":23,"bounds":{"left":0.20578457,"top":0.32960895,"width":0.13380983,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch;","depth":23,"bounds":{"left":0.20578457,"top":0.34876296,"width":0.13380983,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder;","depth":23,"bounds":{"left":0.20578457,"top":0.367917,"width":0.1306516,"height":0.035514764},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder;","depth":23,"bounds":{"left":0.20578457,"top":0.40622506,"width":0.1306516,"height":0.035514764},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\QueuePriorityEnum;","depth":23,"bounds":{"left":0.20578457,"top":0.4828412,"width":0.115359046,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Contracts\\ES\\Events\\UpdateSingleEntity;","depth":23,"bounds":{"left":0.20578457,"top":0.5019952,"width":0.12732713,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Contracts\\ES\\Events\\UpdateSingleEntity;","depth":23,"bounds":{"left":0.20578457,"top":0.5211492,"width":0.12732713,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Psr\\Log\\LoggerInterface;","depth":23,"bounds":{"left":0.20578457,"top":0.5403033,"width":0.07047872,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Psr\\Log\\LoggerInterface;","depth":23,"bounds":{"left":0.20578457,"top":0.5594573,"width":0.07047872,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"'entityId' => $event->getEntityId(),","depth":23,"bounds":{"left":0.20578457,"top":0.6169194,"width":0.08228058,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"'entityId' => $event->getEntityId(),","depth":23,"bounds":{"left":0.20578457,"top":0.6360734,"width":0.08228058,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"]);","depth":23,"bounds":{"left":0.20578457,"top":0.6552275,"width":0.0051529254,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"]);","depth":23,"bounds":{"left":0.20578457,"top":0.6743815,"width":0.0051529254,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/**","depth":23,"bounds":{"left":0.20578457,"top":0.7701516,"width":0.0066489363,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* @important:","depth":23,"bounds":{"left":0.20578457,"top":0.8276137,"width":0.03374335,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* Synchronous event should eventually be deprecated.","depth":23,"bounds":{"left":0.20578457,"top":0.8850758,"width":0.13131648,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* Instant write operations are blocking and should be used sparingly.","depth":23,"bounds":{"left":0.20578457,"top":0.9425379,"width":0.12732713,"height":0.035514764},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* It is much better in terms of performance to write 100 or 1000 documents at once,","depth":23,"bounds":{"left":0.20578457,"top":1.0,"width":0.13314494,"height":-0.019154072},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* and have one blocking reindex operation, instead of writing 10 documents synchronously.","depth":23,"bounds":{"left":0.20578457,"top":1.0,"width":0.12865691,"height":-0.09577012},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"*/","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"if ($event->isSyncEvent()) {","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"if ($event->isSyncEvent()) {","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$this->handleSyncEvent($event);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$this->handleSyncEvent($event);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AsyncUpdateElasticSearch::markEntityForUpdate(","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AsyncUpdateElasticSearch::markEntityForUpdate(","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getUpdateTargetValue(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getUpdateTargetValue(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getEntityId(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getEntityId(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->isPriority()","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL,","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":");","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":");","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app/Component/ES/Processor/Actions/UpsertDocumentsAction.php","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"+2-1Lines changed: 2 additions & 1 deletion","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Processor\\DTOs\\SimpleCollection;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\DTOs\\SimpleCollection;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\ResponseEvaluator;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\ResponseEvaluator;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"}]...
|
5998414489066373319
|
-1127563140626834290
|
click
|
accessibility
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
Close tab
New Tab
Customize sidebar
Close Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
AI Chat settings
Close
WORK, Google Account: [EMAIL]
Main menu
New chat
Gemini
New Chat
Open menu for conversation actions.
Conversation with Gemini
Conversation with Gemini
Show the uploaded image in a lightbox
Copy prompt
You said Make a PR of changes Find potential issues and bottlenecks
You said
Make a PR of changes Find potential issues and bottlenecks
Listen
Show thinking
Gemini said
Gemini said
I can see you've uploaded a screenshot of a code diff, likely from a version control system given the red and green highlights. I would love to help you review the changes, spot bottlenecks, and help you draft a Pull Request.
However,
the image resolution is far too low for me to read.
It appears to be a completely zoomed-out view where the code has been reduced to tiny, illegible pixels. Because of this, I cannot extract any text or logic to analyze.
How You Can Share the Code
How You Can Share the Code
To help me review your code effectively, please try one of the following:
Paste the text directly:
Copy the specific code blocks (both the old and new versions if possible) and paste them directly into our chat.
Upload the files:
If the changes are extensive, you can upload the raw text or code files.
Take high-resolution screenshots:
If you must use images, take closer, readable screenshots of the specific functions or methods you want me to review.
Once you provide the readable code, I can dive right in to identify potential bugs, assess performance bottlenecks, and help you summarize the changes for your PR!
Good response
Bad response
Share & export
Copy
Show more options
Copy prompt
Edit
You said app/Component/ES/Listeners/UpdateMultipleTargetsListener.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\Component\ES\Listeners; namespace Jiminny\Component\ES\Listeners; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Contracts\ES\Events\UpdateMultipleEntities; use Jiminny\Contracts\ES\Events\UpdateMultipleEntities; use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface; AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntities(), $event->getEntities(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } } } app/Component/ES/Listeners/UpdateSingleTargetListener.php +9-1Lines changed: 9 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Actions\TrackElasticSearchOperations; use Jiminny\Component\ES\Actions\TrackElasticSearchOperations; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Contracts\ES\Events\UpdateSingleEntity; use Jiminny\Contracts\ES\Events\UpdateSingleEntity; use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface; 'entityId' => $event->getEntityId(), 'entityId' => $event->getEntityId(), ]); ]); /** * @important: * Synchronous event should eventually be deprecated. * Instant write operations are blocking and should be used sparingly. * It is much better in terms of performance to write 100 or 1000 documents at once, * and have one blocking reindex operation, instead of writing 10 documents synchronously. */ if ($event->isSyncEvent()) { if ($event->isSyncEvent()) { $this->handleSyncEvent($event); $this->handleSyncEvent($event); AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntityId(), $event->getEntityId(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } app/Component/ES/Processor/Actions/UpsertDocumentsAction.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SimpleCollection; use Jiminny\Component\ES\Processor\DTOs\SimpleCollection; use Jiminny\Component\ES\Processor\ResponseEvaluator; use Jiminny\Component\ES\Processor\ResponseEvaluator; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Exceptions\InvalidDataException; use Jiminny\Exceptions\InvalidDataException; use Sentry\Laravel\Facade as Sentry; use Sentry\Laravel\Facade as Sentry; AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( entityType: $this->updateTarget, entityType: $this->updateTarget, entityId: (int) $document->getId(), entityId: (int) $document->getId(), withPriority: true priority: QueuePriorityEnum::HIGH, ); ); } } app/Component/ES/Processor/DTOs/SelectionList.php +54-17Lines changed: 54 additions & 17 deletions Original file line numberOriginal file lineDiff line numberDiff line change namespace Jiminny\Component\ES\Processor\DTOs; namespace Jiminny\Component\ES\Processor\DTOs; use Jiminny\Component\ES\QueuePriorityEnum; /** /** * A very basic and simple collection of entity IDs. * A very basic and simple collection of entity IDs. */ */ class SelectionList class SelectionList { { public function __construct( private const int DEFAULT_CHUNK = 200; private readonly array $priorityEntityIdList = [], private readonly array $normalEntityIdList = [], private int $chunkSize = self::DEFAULT_CHUNK; private readonly bool $isStaleChunkSelected = false, private bool $isStaleChunkSelected = false; private readonly int $chunkSize = 200, private array $selectedEntityIds = []; ) { // Do nothing public function setChunkSize(int $chunkSize): void { $this->chunkSize = $chunkSize; } } public function getAllIds(): array public function markStale(): void { { return array_merge($this->priorityEntityIdList, $this->normalEntityIdList); $this->isStaleChunkSelected = true; } } public function count(): int public function addEntityList(string|QueuePriorityEnum $priority, array $entityIds): void { { return count($this->priorityEntityIdList) + count($this->normalEntityIdList); $priorityKey = $this->normalisePriority($priority); if (! array_key_exists($priorityKey, $this->selectedEntityIds)) { $this->selectedEntityIds[$priorityKey] = []; } $this->selectedEntityIds[$priorityKey] = array_merge($this->selectedEntityIds[$priorityKey], $entityIds); } } public function isEmpty(): bool /** * @return string[] */ public function getEntityListGroups(): array { { return empty($this->priorityEntityIdList) && empty($this->normalEntityIdList); return array_keys($this->selectedEntityIds); } } public function getHighPriorityEntityIds(): array public function getEntityListItemsByGroup(string|QueuePriorityEnum $priority): array { { return $this->priorityEntityIdList; $priorityKey = $this->normalisePriority($priority); return $this->selectedEntityIds[$priorityKey] ?? []; } } public function getNormalPriorityEntityId(): array public function getAllIds(): array { { return $this->normalEntityIdList; $allIds = []; foreach ($this->selectedEntityIds as $entityIds) { $allIds = array_merge($allIds, $entityIds); } return $allIds; } public function count(): int { return array_sum( array_map('count', $this->selectedEntityIds) ); } public function isEmpty(): bool { return $this->count() === 0; } } public function isStaleChunkSelected(): bool public function isStaleChunkSelected(): bool { { return $this->count() >= $this->chunkSize; return $this->count() >= $this->chunkSize; } } private function normalisePriority(string|QueuePriorityEnum $priority): string { return $priority instanceof QueuePriorityEnum ? $priority->value : $priority; } } } app/Component/ES/Processor/Traits/SelectEntityListTrait.php +27-4Lines changed: 27 additions & 4 deletions Original file line numberOriginal file lineDiff line numberDiff line change use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; /** /** * Build the correct source list name for the type of entity and priority * Build the correct source list name for the type of entity and priority */ */ trait SelectEntityListTrait trait SelectEntityListTrait { { /** * Highest priority queue for data requiring near-instant availability. * Very few entities should be added here, only when absolutely necessary. */ private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; /** * Normal priority queue for normal application operations. * Almost all update events should pass through this queue */ private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; protected static function selectTargetList(string $entityType, bool $withPriority = false): string /** { * Nonblocking low priority queue. This queue will be consumed only when there is nothing * with higher priority. * * This queue will be used for operations such as es:reset-async */ private const string ENTITIES_LOW_PRIORITIES_LIST = '%s-for-update-low'; protected static function selectTargetList( string $entityType, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { if (! in_array($entityType, UpdateTarget::allowedTargets())) { if (! in_array($entityType, UpdateTarget::allowedTargets())) { throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); } } if ($withPriority) { if ($priority->isHigh()) { Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); } } if ($priority->isLow()) { return sprintf(self::ENTITIES_LOW_PRIORITIES_LIST, $entityType); } return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); } } } } app/Component/ES/Processor/TargetEntitiesSelector.php +26-21Lines changed: 26 additions & 21 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SelectionList; use Jiminny\Component\ES\Processor\DTOs\SelectionList; use Jiminny\Component\ES\Processor\Traits\ExtractIdsTrait; use Jiminny\Component\ES\Processor\Traits\ExtractIdsTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\QueuePriorityEnum; /** /** * This class supplies a list of entities pending an update. * This class supplies a list of entities pending an update. public function select(): SelectionList public function select(): SelectionList { { $staleWorkEntityIds = $this->getStaleChunk(); $selectionList = new SelectionList(); $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $staleWorkEntityIds = $this->getStaleChunk(); if (count($staleWorkEntityIds) > 0) { if (count($staleWorkEntityIds) > 0) { return new SelectionList( /** priorityEntityIdList: $staleWorkEntityIds, * Stale chunks are treated as high priority isStaleChunkSelected: true, */ chunkSize: ChunkSize::getStaleChunkSize($this->updateTarget), $selectionList->markStale(); ); $selectionList->addEntityList(QueuePriorityEnum::HIGH, $staleWorkEntityIds); $selectionList->setChunkSize(ChunkSize::getStaleChunkSize($this->updateTarget)); return $selectionList; } } $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $selectionList->setChunkSize($mainChunkSize); $priorityEntityIdsList = $this->extractIdsFromSet( $priorityEntityIdsList = $this->extractIds(QueuePriorityEnum::HIGH, $mainChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, true), $selectionList->addEntityList(QueuePriorityEnum::HIGH, $priorityEntityIdsList); $mainChunkSize, ); $normalEntityIdsList = []; $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); if ($normalEntityChunkSize > 0) { if ($normalEntityChunkSize > 0) { $normalEntityIdsList = $this->extractIdsFromSet( $normalEntityIdsList = $this->extractIds(QueuePriorityEnum::NORMAL, $normalEntityChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, false), $selectionList->addEntityList(QueuePriorityEnum::NORMAL, $normalEntityIdsList); $normalEntityChunkSize ); } } return new SelectionList( return $selectionList; priorityEntityIdList: $priorityEntityIdsList, normalEntityIdList: $normalEntityIdsList, chunkSize: $mainChunkSize ); } } private function getStaleChunk(): array private function getStaleChunk(): array return []; return []; } } private function extractIds(QueuePriorityEnum $priority, int $chunkSize): array { return $this->extractIdsFromSet( AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, $priority), $chunkSize ); } } } app/Component/ES/AsyncUpdateElasticSearch.php +17-10Lines changed: 17 additions & 10 deletions Original file line numberOriginal file lineDiff line numberDiff line change * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * and other activity related data * and other activity related data */ */ public static function markEntityForUpdate(string $entityType, int $entityId, bool $withPriority = false): void public static function markEntityForUpdate( { string $entityType, $targetList = self::selectTargetList($entityType, $withPriority); int $entityId, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { $targetList = self::selectTargetList($entityType, $priority); Redis::sadd($targetList, $entityId); Redis::sadd($targetList, $entityId); Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ 'entityType' => $entityType, 'entityType' => $entityType, 'entityId' => $entityId, 'entityId' => $entityId, 'collectionKey' => $targetList, 'collectionKey' => $targetList, 'withPriority' => $withPriority, 'priority' => $priority->value, ]); ]); } } public static function bulkMarkEntitiesForUpdate( public static function bulkMarkEntitiesForUpdate( string $entityType, string $entityType, array $entityIds, array $entityIds, bool $withPriority = false QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { ): void { if (empty($entityIds)) { if (empty($entityIds)) { return; return; } } $targetList = self::selectTargetList($entityType, $withPriority); $targetList = self::selectTargetList($entityType, $priority); Redis::saddarray($targetList, $entityIds); Redis::saddarray($targetList, $entityIds); } } * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Takes priority into consideration. * Takes priority into consideration. */ */ public static function getEntitiesSourceList(string $updateTarget, $priority = false): string public static function getEntitiesSourceList( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { return self::selectTargetList($updateTarget, $priority); return self::selectTargetList($updateTarget, $priority); } } /** /** * Externally called helper methods * Externally called helper methods * - count and flush * - count and flush */ */ public static function getEntitiesListCount(string $updateTarget, $priority = false): int public static function getEntitiesListCount( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): int { $targetList = self::selectTargetList($updateTarget, $priority); $targetList = self::selectTargetList($updateTarget, $priority); return Redis::scard($targetList); return Redis::scard($targetList); app/Component/ES/QueuePriorityEnum.php +40Lines changed: 40 additions & 0 deletions Original file line numberOriginal file lineDiff line numberDiff line change <?php declare(strict_types=1); namespace Jiminny\Component\ES; use Jiminny\Exceptions\InvalidArgumentException; enum QueuePriorityEnum: string { case HIGH = 'high'; case NORMAL = 'normal'; case LOW = 'low'; public static function tryFromString(string $value): self { if (! self::isValid($value)) { throw new InvalidArgumentException( sprintf('Invalid queue priority "%s" selected', $value) ); } return self::tryFrom($value); } public static function isValid(string $value): bool { return self::tryFrom($value) !== null; } public function isLow(): bool { return $this === self::LOW; } public function isHigh(): bool { return $this === self::HIGH; } } app/Component/ES/UpdateProcessManager.php +12-9Lines changed: 12 additions & 9 deletions Original file line numberOriginal file lineDiff line numberDiff line change if ($selectionList->isEmpty()) { if ($selectionList->isEmpty()) { return false; return false; } } /** /** * A stale chunk will always be smaller than a regular chunk. * A stale chunk will always be smaller than a regular chunk. * That doesn't mean there aren't any other scheduled entities for processing * That doesn't mean there aren't any other scheduled entities for processing private function rescheduleThrottledEntities(SelectionList $selectionList): void private function rescheduleThrottledEntities(SelectionList $selectionList): void { { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $groups = $selectionList->getEntityListGroups(); $this->updateTarget, foreach ($groups as $eachGroup) { $selectionList->getNormalPriorityEntityId() $groupEntityIds = $selectionList->getEntityListItemsByGroup($eachGroup); ); if (! empty($groupEntityIds)) { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $this->updateTarget, entityType: $this->updateTarget, $selectionList->getHighPriorityEntityIds(), entityIds: $groupEntityIds, true priority: QueuePriorityEnum::tryFromString($eachGroup) ); ); } } } } } } app/Console/Commands/Elasticsearch/AsyncUpdateEsEntities.php +9-3Lines changed: 9 additions & 3 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Illuminate\Support\Str; use Illuminate\Support\Str; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Component\ES\UpdateProcessManager; use Jiminny\Component\ES\UpdateProcessManager; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Traits\GracefullyStoppable; use Jiminny\Traits\GracefullyStoppable; Redis::set($gaugeLockName, true); Redis::set($gaugeLockName, true); Redis::expire($gaugeLockName, 60); Redis::expire($gaugeLockName, 60); $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::HIGH), ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update', $updateTarget), stat: sprintf('jiminny.%s-for-update', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::NORMAL), ); ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), stat: sprintf('jiminny.%s-for-update-low', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, true), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::LOW), ); ); } } app/Console/Commands/Elasticsearch/ResetAsyncElasticSearchCommand.php +5-1Lines changed: 5 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\Traits\ValidateUpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\ValidateUpdateTargetTrait; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Component\ES\Repositories\EsResetRepositoryInterface; use Jiminny\Component\ES\Repositories\EsResetRepositoryInterface; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Traits\GracefullyStoppable; use Jiminny\Traits\GracefullyStoppable; private function getRemainingScheduledEntities(bool $printStatus = false): int private function getRemainingScheduledEntities(bool $printStatus = false): int { { $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget, true); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount( $this->updateTarget, QueuePriorityEnum::HIGH ); if ($printStatus) { if ($printStatus) { $this->line( $this->line(
You said
app/Component/ES/Listeners/UpdateMultipleTargetsListener.php
+2-1Lines changed: 2 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\Component\ES\Listeners;
namespace Jiminny\Component\ES\Listeners;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\QueuePriorityEnum;
use Jiminny\Contracts\ES\Events\UpdateMultipleEntities;
use Jiminny\Contracts\ES\Events\UpdateMultipleEntities;
use Psr\Log\LoggerInterface;
use Psr\Log\LoggerInterface;
AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(
AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(
$event->getUpdateTargetValue(),
$event->getUpdateTargetValue(),
$event->getEntities(),
$event->getEntities(),
$event->isPriority()
$event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL,
);
);
}
}
}
}
app/Component/ES/Listeners/UpdateSingleTargetListener.php
+9-1Lines changed: 9 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Actions\TrackElasticSearchOperations;
use Jiminny\Component\ES\Actions\TrackElasticSearchOperations;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\Processor\EntityQueryBuilder;
use Jiminny\Component\ES\Processor\EntityQueryBuilder;
use Jiminny\Component\ES\QueuePriorityEnum;
use Jiminny\Contracts\ES\Events\UpdateSingleEntity;
use Jiminny\Contracts\ES\Events\UpdateSingleEntity;
use Psr\Log\LoggerInterface;
use Psr\Log\LoggerInterface;
'entityId' => $event->getEntityId(),
'entityId' => $event->getEntityId(),
]);
]);
/**
* @important:
* Synchronous event should eventually be deprecated.
* Instant write operations are blocking and should be used sparingly.
* It is much better in terms of performance to write 100 or 1000 documents at once,
* and have one blocking reindex operation, instead of writing 10 documents synchronously.
*/
if ($event->isSyncEvent()) {
if ($event->isSyncEvent()) {
$this->handleSyncEvent($event);
$this->handleSyncEvent($event);
AsyncUpdateElasticSearch::markEntityForUpdate(
AsyncUpdateElasticSearch::markEntityForUpdate(
$event->getUpdateTargetValue(),
$event->getUpdateTargetValue(),
$event->getEntityId(),
$event->getEntityId(),
$event->isPriority()
$event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL,
);
);
}
}
app/Component/ES/Processor/Actions/UpsertDocumentsAction.php
+2-1Lines changed: 2 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SimpleCollection;
use Jiminny\Component\ES\Processor\DTOs\SimpleCollection;
use Jiminny\Component\ES\Processor\ResponseEvaluator;
use Jiminny\Component\ES\Processor\ResponseEvaluator;
use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait;
use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait;...
|
55694
|
NULL
|
NULL
|
NULL
|
|
55698
|
1935
|
1
|
2026-05-19T06:42:22.431624+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779172942431_m2.jpg...
|
Firefox
|
JY-20808 low priority indexing queue by Vasil-Jimi JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app — Work...
|
1
|
github.com/jiminny/app/pull/12082/changes#diff-eea github.com/jiminny/app/pull/12082/changes#diff-eeacd403a912dc6a384056b3fd5356e90255c2794f5665a40bbda5c683098397...
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
Close tab
New Tab
Customize sidebar
Close Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
AI Chat settings
Close
WORK, Google Account: [EMAIL]
Main menu
New chat
Gemini
New Chat
Open menu for conversation actions.
Conversation with Gemini
Conversation with Gemini
Show the uploaded image in a lightbox
Copy prompt
You said Make a PR of changes Find potential issues and bottlenecks
You said
Make a PR of changes Find potential issues and bottlenecks
Listen
Show thinking
Gemini said
Gemini said
I can see you've uploaded a screenshot of a code diff, likely from a version control system given the red and green highlights. I would love to help you review the changes, spot bottlenecks, and help you draft a Pull Request.
However,
the image resolution is far too low for me to read.
It appears to be a completely zoomed-out view where the code has been reduced to tiny, illegible pixels. Because of this, I cannot extract any text or logic to analyze.
How You Can Share the Code
How You Can Share the Code
To help me review your code effectively, please try one of the following:
Paste the text directly:
Copy the specific code blocks (both the old and new versions if possible) and paste them directly into our chat.
Upload the files:
If the changes are extensive, you can upload the raw text or code files.
Take high-resolution screenshots:
If you must use images, take closer, readable screenshots of the specific functions or methods you want me to review.
Once you provide the readable code, I can dive right in to identify potential bugs, assess performance bottlenecks, and help you summarize the changes for your PR!
Good response
Bad response
Share & export
Copy
Show more options
Copy prompt
Edit
You said app/Component/ES/Listeners/UpdateMultipleTargetsListener.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\Component\ES\Listeners; namespace Jiminny\Component\ES\Listeners; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Contracts\ES\Events\UpdateMultipleEntities; use Jiminny\Contracts\ES\Events\UpdateMultipleEntities; use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface; AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntities(), $event->getEntities(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } } } app/Component/ES/Listeners/UpdateSingleTargetListener.php +9-1Lines changed: 9 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Actions\TrackElasticSearchOperations; use Jiminny\Component\ES\Actions\TrackElasticSearchOperations; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Contracts\ES\Events\UpdateSingleEntity; use Jiminny\Contracts\ES\Events\UpdateSingleEntity; use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface; 'entityId' => $event->getEntityId(), 'entityId' => $event->getEntityId(), ]); ]); /** * @important: * Synchronous event should eventually be deprecated. * Instant write operations are blocking and should be used sparingly. * It is much better in terms of performance to write 100 or 1000 documents at once, * and have one blocking reindex operation, instead of writing 10 documents synchronously. */ if ($event->isSyncEvent()) { if ($event->isSyncEvent()) { $this->handleSyncEvent($event); $this->handleSyncEvent($event); AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntityId(), $event->getEntityId(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } app/Component/ES/Processor/Actions/UpsertDocumentsAction.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SimpleCollection; use Jiminny\Component\ES\Processor\DTOs\SimpleCollection; use Jiminny\Component\ES\Processor\ResponseEvaluator; use Jiminny\Component\ES\Processor\ResponseEvaluator; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Exceptions\InvalidDataException; use Jiminny\Exceptions\InvalidDataException; use Sentry\Laravel\Facade as Sentry; use Sentry\Laravel\Facade as Sentry; AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( entityType: $this->updateTarget, entityType: $this->updateTarget, entityId: (int) $document->getId(), entityId: (int) $document->getId(), withPriority: true priority: QueuePriorityEnum::HIGH, ); ); } } app/Component/ES/Processor/DTOs/SelectionList.php +54-17Lines changed: 54 additions & 17 deletions Original file line numberOriginal file lineDiff line numberDiff line change namespace Jiminny\Component\ES\Processor\DTOs; namespace Jiminny\Component\ES\Processor\DTOs; use Jiminny\Component\ES\QueuePriorityEnum; /** /** * A very basic and simple collection of entity IDs. * A very basic and simple collection of entity IDs. */ */ class SelectionList class SelectionList { { public function __construct( private const int DEFAULT_CHUNK = 200; private readonly array $priorityEntityIdList = [], private readonly array $normalEntityIdList = [], private int $chunkSize = self::DEFAULT_CHUNK; private readonly bool $isStaleChunkSelected = false, private bool $isStaleChunkSelected = false; private readonly int $chunkSize = 200, private array $selectedEntityIds = []; ) { // Do nothing public function setChunkSize(int $chunkSize): void { $this->chunkSize = $chunkSize; } } public function getAllIds(): array public function markStale(): void { { return array_merge($this->priorityEntityIdList, $this->normalEntityIdList); $this->isStaleChunkSelected = true; } } public function count(): int public function addEntityList(string|QueuePriorityEnum $priority, array $entityIds): void { { return count($this->priorityEntityIdList) + count($this->normalEntityIdList); $priorityKey = $this->normalisePriority($priority); if (! array_key_exists($priorityKey, $this->selectedEntityIds)) { $this->selectedEntityIds[$priorityKey] = []; } $this->selectedEntityIds[$priorityKey] = array_merge($this->selectedEntityIds[$priorityKey], $entityIds); } } public function isEmpty(): bool /** * @return string[] */ public function getEntityListGroups(): array { { return empty($this->priorityEntityIdList) && empty($this->normalEntityIdList); return array_keys($this->selectedEntityIds); } } public function getHighPriorityEntityIds(): array public function getEntityListItemsByGroup(string|QueuePriorityEnum $priority): array { { return $this->priorityEntityIdList; $priorityKey = $this->normalisePriority($priority); return $this->selectedEntityIds[$priorityKey] ?? []; } } public function getNormalPriorityEntityId(): array public function getAllIds(): array { { return $this->normalEntityIdList; $allIds = []; foreach ($this->selectedEntityIds as $entityIds) { $allIds = array_merge($allIds, $entityIds); } return $allIds; } public function count(): int { return array_sum( array_map('count', $this->selectedEntityIds) ); } public function isEmpty(): bool { return $this->count() === 0; } } public function isStaleChunkSelected(): bool public function isStaleChunkSelected(): bool { { return $this->count() >= $this->chunkSize; return $this->count() >= $this->chunkSize; } } private function normalisePriority(string|QueuePriorityEnum $priority): string { return $priority instanceof QueuePriorityEnum ? $priority->value : $priority; } } } app/Component/ES/Processor/Traits/SelectEntityListTrait.php +27-4Lines changed: 27 additions & 4 deletions Original file line numberOriginal file lineDiff line numberDiff line change use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; /** /** * Build the correct source list name for the type of entity and priority * Build the correct source list name for the type of entity and priority */ */ trait SelectEntityListTrait trait SelectEntityListTrait { { /** * Highest priority queue for data requiring near-instant availability. * Very few entities should be added here, only when absolutely necessary. */ private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; /** * Normal priority queue for normal application operations. * Almost all update events should pass through this queue */ private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; protected static function selectTargetList(string $entityType, bool $withPriority = false): string /** { * Nonblocking low priority queue. This queue will be consumed only when there is nothing * with higher priority. * * This queue will be used for operations such as es:reset-async */ private const string ENTITIES_LOW_PRIORITIES_LIST = '%s-for-update-low'; protected static function selectTargetList( string $entityType, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { if (! in_array($entityType, UpdateTarget::allowedTargets())) { if (! in_array($entityType, UpdateTarget::allowedTargets())) { throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); } } if ($withPriority) { if ($priority->isHigh()) { Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); } } if ($priority->isLow()) { return sprintf(self::ENTITIES_LOW_PRIORITIES_LIST, $entityType); } return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); } } } } app/Component/ES/Processor/TargetEntitiesSelector.php +26-21Lines changed: 26 additions & 21 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SelectionList; use Jiminny\Component\ES\Processor\DTOs\SelectionList; use Jiminny\Component\ES\Processor\Traits\ExtractIdsTrait; use Jiminny\Component\ES\Processor\Traits\ExtractIdsTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\QueuePriorityEnum; /** /** * This class supplies a list of entities pending an update. * This class supplies a list of entities pending an update. public function select(): SelectionList public function select(): SelectionList { { $staleWorkEntityIds = $this->getStaleChunk(); $selectionList = new SelectionList(); $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $staleWorkEntityIds = $this->getStaleChunk(); if (count($staleWorkEntityIds) > 0) { if (count($staleWorkEntityIds) > 0) { return new SelectionList( /** priorityEntityIdList: $staleWorkEntityIds, * Stale chunks are treated as high priority isStaleChunkSelected: true, */ chunkSize: ChunkSize::getStaleChunkSize($this->updateTarget), $selectionList->markStale(); ); $selectionList->addEntityList(QueuePriorityEnum::HIGH, $staleWorkEntityIds); $selectionList->setChunkSize(ChunkSize::getStaleChunkSize($this->updateTarget)); return $selectionList; } } $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $selectionList->setChunkSize($mainChunkSize); $priorityEntityIdsList = $this->extractIdsFromSet( $priorityEntityIdsList = $this->extractIds(QueuePriorityEnum::HIGH, $mainChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, true), $selectionList->addEntityList(QueuePriorityEnum::HIGH, $priorityEntityIdsList); $mainChunkSize, ); $normalEntityIdsList = []; $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); if ($normalEntityChunkSize > 0) { if ($normalEntityChunkSize > 0) { $normalEntityIdsList = $this->extractIdsFromSet( $normalEntityIdsList = $this->extractIds(QueuePriorityEnum::NORMAL, $normalEntityChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, false), $selectionList->addEntityList(QueuePriorityEnum::NORMAL, $normalEntityIdsList); $normalEntityChunkSize ); } } return new SelectionList( return $selectionList; priorityEntityIdList: $priorityEntityIdsList, normalEntityIdList: $normalEntityIdsList, chunkSize: $mainChunkSize ); } } private function getStaleChunk(): array private function getStaleChunk(): array return []; return []; } } private function extractIds(QueuePriorityEnum $priority, int $chunkSize): array { return $this->extractIdsFromSet( AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, $priority), $chunkSize ); } } } app/Component/ES/AsyncUpdateElasticSearch.php +17-10Lines changed: 17 additions & 10 deletions Original file line numberOriginal file lineDiff line numberDiff line change * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * and other activity related data * and other activity related data */ */ public static function markEntityForUpdate(string $entityType, int $entityId, bool $withPriority = false): void public static function markEntityForUpdate( { string $entityType, $targetList = self::selectTargetList($entityType, $withPriority); int $entityId, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { $targetList = self::selectTargetList($entityType, $priority); Redis::sadd($targetList, $entityId); Redis::sadd($targetList, $entityId); Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ 'entityType' => $entityType, 'entityType' => $entityType, 'entityId' => $entityId, 'entityId' => $entityId, 'collectionKey' => $targetList, 'collectionKey' => $targetList, 'withPriority' => $withPriority, 'priority' => $priority->value, ]); ]); } } public static function bulkMarkEntitiesForUpdate( public static function bulkMarkEntitiesForUpdate( string $entityType, string $entityType, array $entityIds, array $entityIds, bool $withPriority = false QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { ): void { if (empty($entityIds)) { if (empty($entityIds)) { return; return; } } $targetList = self::selectTargetList($entityType, $withPriority); $targetList = self::selectTargetList($entityType, $priority); Redis::saddarray($targetList, $entityIds); Redis::saddarray($targetList, $entityIds); } } * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Takes priority into consideration. * Takes priority into consideration. */ */ public static function getEntitiesSourceList(string $updateTarget, $priority = false): string public static function getEntitiesSourceList( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { return self::selectTargetList($updateTarget, $priority); return self::selectTargetList($updateTarget, $priority); } } /** /** * Externally called helper methods * Externally called helper methods * - count and flush * - count and flush */ */ public static function getEntitiesListCount(string $updateTarget, $priority = false): int public static function getEntitiesListCount( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): int { $targetList = self::selectTargetList($updateTarget, $priority); $targetList = self::selectTargetList($updateTarget, $priority); return Redis::scard($targetList); return Redis::scard($targetList); app/Component/ES/QueuePriorityEnum.php +40Lines changed: 40 additions & 0 deletions Original file line numberOriginal file lineDiff line numberDiff line change <?php declare(strict_types=1); namespace Jiminny\Component\ES; use Jiminny\Exceptions\InvalidArgumentException; enum QueuePriorityEnum: string { case HIGH = 'high'; case NORMAL = 'normal'; case LOW = 'low'; public static function tryFromString(string $value): self { if (! self::isValid($value)) { throw new InvalidArgumentException( sprintf('Invalid queue priority "%s" selected', $value) ); } return self::tryFrom($value); } public static function isValid(string $value): bool { return self::tryFrom($value) !== null; } public function isLow(): bool { return $this === self::LOW; } public function isHigh(): bool { return $this === self::HIGH; } } app/Component/ES/UpdateProcessManager.php +12-9Lines changed: 12 additions & 9 deletions Original file line numberOriginal file lineDiff line numberDiff line change if ($selectionList->isEmpty()) { if ($selectionList->isEmpty()) { return false; return false; } } /** /** * A stale chunk will always be smaller than a regular chunk. * A stale chunk will always be smaller than a regular chunk. * That doesn't mean there aren't any other scheduled entities for processing * That doesn't mean there aren't any other scheduled entities for processing private function rescheduleThrottledEntities(SelectionList $selectionList): void private function rescheduleThrottledEntities(SelectionList $selectionList): void { { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $groups = $selectionList->getEntityListGroups(); $this->updateTarget, foreach ($groups as $eachGroup) { $selectionList->getNormalPriorityEntityId() $groupEntityIds = $selectionList->getEntityListItemsByGroup($eachGroup); ); if (! empty($groupEntityIds)) { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $this->updateTarget, entityType: $this->updateTarget, $selectionList->getHighPriorityEntityIds(), entityIds: $groupEntityIds, true priority: QueuePriorityEnum::tryFromString($eachGroup) ); ); } } } } } } app/Console/Commands/Elasticsearch/AsyncUpdateEsEntities.php +9-3Lines changed: 9 additions & 3 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Illuminate\Support\Str; use Illuminate\Support\Str; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Component\ES\UpdateProcessManager; use Jiminny\Component\ES\UpdateProcessManager; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Traits\GracefullyStoppable; use Jiminny\Traits\GracefullyStoppable; Redis::set($gaugeLockName, true); Redis::set($gaugeLockName, true); Redis::expire($gaugeLockName, 60); Redis::expire($gaugeLockName, 60); $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::HIGH), ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update', $updateTarget), stat: sprintf('jiminny.%s-for-update', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::NORMAL), ); ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), stat: sprintf('jiminny.%s-for-update-low', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, true), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::LOW), ); ); } } app/Console/Commands/Elasticsearch/ResetAsyncElasticSearchCommand.php +5-1Lines changed: 5 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\Traits\ValidateUpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\ValidateUpdateTargetTrait; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Component\ES\Repositories\EsResetRepositoryInterface; use Jiminny\Component\ES\Repositories\EsResetRepositoryInterface; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Traits\GracefullyStoppable; use Jiminny\Traits\GracefullyStoppable; private function getRemainingScheduledEntities(bool $printStatus = false): int private function getRemainingScheduledEntities(bool $printStatus = false): int { { $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget, true); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount( $this->updateTarget, QueuePriorityEnum::HIGH ); if ($printStatus) { if ($printStatus) { $this->line( $this->line(
You said
app/Component/ES/Listeners/UpdateMultipleTargetsListener.php
+2-1Lines changed: 2 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\Component\ES\Listeners;
namespace Jiminny\Component\ES\Listeners;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\QueuePriorityEnum;
use Jiminny\Contracts\ES\Events\UpdateMultipleEntities;
use Jiminny\Contracts\ES\Events\UpdateMultipleEntities;
use Psr\Log\LoggerInterface;
use Psr\Log\LoggerInterface;
AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(
AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(
$event->getUpdateTargetValue(),
$event->getUpdateTargetValue(),
$event->getEntities(),
$event->getEntities(),
$event->isPriority()
$event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL,
);
);
}
}
}
}
app/Component/ES/Listeners/UpdateSingleTargetListener.php
+9-1Lines changed: 9 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Actions\TrackElasticSearchOperations;
use Jiminny\Component\ES\Actions\TrackElasticSearchOperations;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\Processor\EntityQueryBuilder;
use Jiminny\Component\ES\Processor\EntityQueryBuilder;
use Jiminny\Component\ES\QueuePriorityEnum;
use Jiminny\Contracts\ES\Events\UpdateSingleEntity;
use Jiminny\Contracts\ES\Events\UpdateSingleEntity;
use Psr\Log\LoggerInterface;
use Psr\Log\LoggerInterface;
'entityId' => $event->getEntityId(),
'entityId' => $event->getEntityId(),
]);
]);
/**
* @important:
* Synchronous event should eventually be deprecated.
* Instant write operations are blocking and should be used sparingly.
* It is much better in terms of performance to write 100 or 1000 documents at once,
* and have one blocking reindex operation, instead of writing 10 documents synchronously.
*/
if ($event->isSyncEvent()) {
if ($event->isSyncEvent()) {
$this->handleSyncEvent($event);
$this->handleSyncEvent($event);
AsyncUpdateElasticSearch::markEntityForUpdate(
AsyncUpdateElasticSearch::markEntityForUpdate(
$event->getUpdateTargetValue(),
$event->getUpdateTargetValue(),
$event->getEntityId(),
$event->getEntityId(),
$event->isPriority()
$event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL,
);
);
}
}
app/Component/ES/Processor/Actions/UpsertDocumentsAction.php
+2-1Lines changed: 2 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SimpleCollection;
use Jiminny\Component\ES\Processor\DTOs\SimpleCollection;
use Jiminny\Component\ES\Processor\ResponseEvaluator;
use Jiminny\Component\ES\Processor\ResponseEvaluator;
use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait;
use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait;
use Jiminny\Component\ES\QueuePriorityEnum;
use Jiminny\Exceptions\InvalidDataException;
use Jiminny\Exceptions\InvalidDataException;
use Sentry\Laravel\Facade as Sentry;
use Sentry\Laravel\Facade as Sentry;
AsyncUpdateElasticSearch::markEntityForUpdate(
AsyncUpdateElasticSearch::markEntityForUpdate(
entityType: $this->updateTarget,
entityType: $this->updateTarget,
entityId: (int) $document->getId(),
entityId: (int) $document->getId(),
withPriority: true
priority: QueuePriorityEnum::HIGH,
);
);
}
}
app/Component/ES/Processor/DTOs/SelectionList.php
+54-17Lines changed: 54 additions & 17 deletions
Original file line numberOriginal file lineDiff line numberDiff line change
namespace Jiminny\Component\ES\Processor\DTOs;
namespace Jiminny\Component\ES\Processor\DTOs;
use Jiminny\Component\ES\QueuePriorityEnum;
/**
/**
* A very basic and simple collection of entity IDs.
* A very basic and simple collection of entity IDs.
*/
*/
class SelectionList
class SelectionList
{
{
public function __construct(
private const int DEFAULT_CHUNK = 200;
private readonly array $priorityEntityIdList = [],
private readonly array $normalEntityIdList = [],
private int $chunkSize = self::DEFAULT_CHUNK;
private readonly bool $isStaleChunkSelected = false,
private bool $isStaleChunkSelected = false;
private readonly int $chunkSize = 200,
private array $selectedEntityIds = [];
) {
// Do nothing
public function setChunkSize(int $chunkSize): void
{
$this->chunkSize = $chunkSize;
}
}
public function getAllIds(): array
public function markStale(): void
{
{
return array_merge($this->priorityEntityIdList, $this->normalEntityIdList);
$this->isStaleChunkSelected = true;
}
}
public function count(): int
public function addEntityList(string|QueuePriorityEnum $priority, array $entityIds): void
{
{
return count($this->priorityEntityIdList) + count($this->normalEntityIdList);
$priorityKey = $this->normalisePriority($priority);
if (! array_key_exists($priorityKey, $this->selectedEntityIds)) {
$this->selectedEntityIds[$priorityKey] = [];
}
$this->selectedEntityIds[$priorityKey] = array_merge($this->selectedEntityIds[$priorityKey], $entityIds);
}
}
public function isEmpty(): bool
/**
* @return string[]
*/
public function getEntityListGroups(): array
{
{
return empty($this->priorityEntityIdList) && empty($this->normalEntityIdList);
return array_keys($this->selectedEntityIds);
}
}
public function getHighPriorityEntityIds(): array
public function getEntityListItemsByGroup(string|QueuePriorityEnum $priority): array
{
{
return $this->priorityEntityIdList;
$priorityKey = $this->normalisePriority($priority);
return $this->selectedEntityIds[$priorityKey] ?? [];
}
}
public function getNormalPriorityEntityId(): array
public function getAllIds(): array
{
{
return $this->normalEntityIdList;
$allIds = [];
foreach ($this->selectedEntityIds as $entityIds) {
$allIds = array_merge($allIds, $entityIds);
}
return $allIds;...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira","depth":4,"bounds":{"left":0.0,"top":0.0518755,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.06304868,"width":0.10106383,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app","depth":4,"bounds":{"left":0.0,"top":0.08459697,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app","depth":5,"bounds":{"left":0.013297873,"top":0.09577015,"width":0.18816489,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app","depth":4,"bounds":{"left":0.0,"top":0.11731844,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app","depth":5,"bounds":{"left":0.013297873,"top":0.12849163,"width":0.15674867,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.06732048,"top":0.1245012,"width":0.007978723,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New Tab","depth":4,"bounds":{"left":0.0028257978,"top":0.15163608,"width":0.07413564,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"bounds":{"left":0.0028257978,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Close Google Gemini (⌃X)","depth":6,"bounds":{"left":0.013796543,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Tabs from other devices","depth":6,"bounds":{"left":0.024933511,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"bounds":{"left":0.036070477,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"bounds":{"left":0.04720745,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"AI Chat settings","depth":7,"bounds":{"left":0.35854387,"top":0.055067837,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Close","depth":7,"bounds":{"left":0.37051198,"top":0.055067837,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"WORK, Google Account: lukas.kovalik@jiminny.com","depth":12,"bounds":{"left":0.3678524,"top":0.103751,"width":0.013297873,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Main menu","depth":12,"bounds":{"left":0.08494016,"top":0.103751,"width":0.013297873,"height":0.031923383},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New chat","depth":12,"bounds":{"left":0.09823803,"top":0.10454908,"width":0.028590426,"height":0.030327214},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Gemini","depth":15,"bounds":{"left":0.1008976,"top":0.10973663,"width":0.021941489,"height":0.020351157},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"New Chat","depth":12,"bounds":{"left":0.33992687,"top":0.103751,"width":0.013297873,"height":0.031923383},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Open menu for conversation actions.","depth":12,"bounds":{"left":0.35322472,"top":0.103751,"width":0.013297873,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXHeading","text":"Conversation with Gemini","depth":15,"bounds":{"left":0.079288565,"top":0.14764565,"width":0.0003324468,"height":0.0007980846},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Conversation with Gemini","depth":16,"bounds":{"left":0.079288565,"top":0.15003991,"width":0.1200133,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Show the uploaded image in a lightbox","depth":21,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy prompt","depth":21,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"You said Make a PR of changes Find potential issues and bottlenecks","depth":21,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"You said","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Make a PR of changes Find potential issues and bottlenecks","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Listen","depth":22,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Show thinking","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Gemini said","depth":20,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Gemini said","depth":21,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"I can see you've uploaded a screenshot of a code diff, likely from a version control system given the red and green highlights. I would love to help you review the changes, spot bottlenecks, and help you draft a Pull Request.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"However,","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"the image resolution is far too low for me to read.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"It appears to be a completely zoomed-out view where the code has been reduced to tiny, illegible pixels. Because of this, I cannot extract any text or logic to analyze.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"How You Can Share the Code","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"How You Can Share the Code","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"To help me review your code effectively, please try one of the following:","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Paste the text directly:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Copy the specific code blocks (both the old and new versions if possible) and paste them directly into our chat.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Upload the files:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"If the changes are extensive, you can upload the raw text or code files.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Take high-resolution screenshots:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"If you must use images, take closer, readable screenshots of the specific functions or methods you want me to review.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Once you provide the readable code, I can dive right in to identify potential bugs, assess performance bottlenecks, and help you summarize the changes for your PR!","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Good response","depth":22,"on_screen":false,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Bad response","depth":22,"on_screen":false,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Share & export","depth":21,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy","depth":22,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Show more options","depth":21,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy prompt","depth":21,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Edit","depth":21,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"You said app/Component/ES/Listeners/UpdateMultipleTargetsListener.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\\Component\\ES\\Listeners; namespace Jiminny\\Component\\ES\\Listeners; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Contracts\\ES\\Events\\UpdateMultipleEntities; use Jiminny\\Contracts\\ES\\Events\\UpdateMultipleEntities; use Psr\\Log\\LoggerInterface; use Psr\\Log\\LoggerInterface; AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntities(), $event->getEntities(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } } } app/Component/ES/Listeners/UpdateSingleTargetListener.php +9-1Lines changed: 9 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Actions\\TrackElasticSearchOperations; use Jiminny\\Component\\ES\\Actions\\TrackElasticSearchOperations; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder; use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Contracts\\ES\\Events\\UpdateSingleEntity; use Jiminny\\Contracts\\ES\\Events\\UpdateSingleEntity; use Psr\\Log\\LoggerInterface; use Psr\\Log\\LoggerInterface; 'entityId' => $event->getEntityId(), 'entityId' => $event->getEntityId(), ]); ]); /** * @important: * Synchronous event should eventually be deprecated. * Instant write operations are blocking and should be used sparingly. * It is much better in terms of performance to write 100 or 1000 documents at once, * and have one blocking reindex operation, instead of writing 10 documents synchronously. */ if ($event->isSyncEvent()) { if ($event->isSyncEvent()) { $this->handleSyncEvent($event); $this->handleSyncEvent($event); AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntityId(), $event->getEntityId(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } app/Component/ES/Processor/Actions/UpsertDocumentsAction.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Processor\\DTOs\\SimpleCollection; use Jiminny\\Component\\ES\\Processor\\DTOs\\SimpleCollection; use Jiminny\\Component\\ES\\Processor\\ResponseEvaluator; use Jiminny\\Component\\ES\\Processor\\ResponseEvaluator; use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait; use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Exceptions\\InvalidDataException; use Jiminny\\Exceptions\\InvalidDataException; use Sentry\\Laravel\\Facade as Sentry; use Sentry\\Laravel\\Facade as Sentry; AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( entityType: $this->updateTarget, entityType: $this->updateTarget, entityId: (int) $document->getId(), entityId: (int) $document->getId(), withPriority: true priority: QueuePriorityEnum::HIGH, ); ); } } app/Component/ES/Processor/DTOs/SelectionList.php +54-17Lines changed: 54 additions & 17 deletions Original file line numberOriginal file lineDiff line numberDiff line change namespace Jiminny\\Component\\ES\\Processor\\DTOs; namespace Jiminny\\Component\\ES\\Processor\\DTOs; use Jiminny\\Component\\ES\\QueuePriorityEnum; /** /** * A very basic and simple collection of entity IDs. * A very basic and simple collection of entity IDs. */ */ class SelectionList class SelectionList { { public function __construct( private const int DEFAULT_CHUNK = 200; private readonly array $priorityEntityIdList = [], private readonly array $normalEntityIdList = [], private int $chunkSize = self::DEFAULT_CHUNK; private readonly bool $isStaleChunkSelected = false, private bool $isStaleChunkSelected = false; private readonly int $chunkSize = 200, private array $selectedEntityIds = []; ) { // Do nothing public function setChunkSize(int $chunkSize): void { $this->chunkSize = $chunkSize; } } public function getAllIds(): array public function markStale(): void { { return array_merge($this->priorityEntityIdList, $this->normalEntityIdList); $this->isStaleChunkSelected = true; } } public function count(): int public function addEntityList(string|QueuePriorityEnum $priority, array $entityIds): void { { return count($this->priorityEntityIdList) + count($this->normalEntityIdList); $priorityKey = $this->normalisePriority($priority); if (! array_key_exists($priorityKey, $this->selectedEntityIds)) { $this->selectedEntityIds[$priorityKey] = []; } $this->selectedEntityIds[$priorityKey] = array_merge($this->selectedEntityIds[$priorityKey], $entityIds); } } public function isEmpty(): bool /** * @return string[] */ public function getEntityListGroups(): array { { return empty($this->priorityEntityIdList) && empty($this->normalEntityIdList); return array_keys($this->selectedEntityIds); } } public function getHighPriorityEntityIds(): array public function getEntityListItemsByGroup(string|QueuePriorityEnum $priority): array { { return $this->priorityEntityIdList; $priorityKey = $this->normalisePriority($priority); return $this->selectedEntityIds[$priorityKey] ?? []; } } public function getNormalPriorityEntityId(): array public function getAllIds(): array { { return $this->normalEntityIdList; $allIds = []; foreach ($this->selectedEntityIds as $entityIds) { $allIds = array_merge($allIds, $entityIds); } return $allIds; } public function count(): int { return array_sum( array_map('count', $this->selectedEntityIds) ); } public function isEmpty(): bool { return $this->count() === 0; } } public function isStaleChunkSelected(): bool public function isStaleChunkSelected(): bool { { return $this->count() >= $this->chunkSize; return $this->count() >= $this->chunkSize; } } private function normalisePriority(string|QueuePriorityEnum $priority): string { return $priority instanceof QueuePriorityEnum ? $priority->value : $priority; } } } app/Component/ES/Processor/Traits/SelectEntityListTrait.php +27-4Lines changed: 27 additions & 4 deletions Original file line numberOriginal file lineDiff line numberDiff line change use Illuminate\\Support\\Facades\\Log; use Illuminate\\Support\\Facades\\Log; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Exceptions\\InvalidArgumentException; use Jiminny\\Exceptions\\InvalidArgumentException; /** /** * Build the correct source list name for the type of entity and priority * Build the correct source list name for the type of entity and priority */ */ trait SelectEntityListTrait trait SelectEntityListTrait { { /** * Highest priority queue for data requiring near-instant availability. * Very few entities should be added here, only when absolutely necessary. */ private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; /** * Normal priority queue for normal application operations. * Almost all update events should pass through this queue */ private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; protected static function selectTargetList(string $entityType, bool $withPriority = false): string /** { * Nonblocking low priority queue. This queue will be consumed only when there is nothing * with higher priority. * * This queue will be used for operations such as es:reset-async */ private const string ENTITIES_LOW_PRIORITIES_LIST = '%s-for-update-low'; protected static function selectTargetList( string $entityType, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { if (! in_array($entityType, UpdateTarget::allowedTargets())) { if (! in_array($entityType, UpdateTarget::allowedTargets())) { throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); } } if ($withPriority) { if ($priority->isHigh()) { Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); } } if ($priority->isLow()) { return sprintf(self::ENTITIES_LOW_PRIORITIES_LIST, $entityType); } return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); } } } } app/Component/ES/Processor/TargetEntitiesSelector.php +26-21Lines changed: 26 additions & 21 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Processor\\DTOs\\SelectionList; use Jiminny\\Component\\ES\\Processor\\DTOs\\SelectionList; use Jiminny\\Component\\ES\\Processor\\Traits\\ExtractIdsTrait; use Jiminny\\Component\\ES\\Processor\\Traits\\ExtractIdsTrait; use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait; use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait; use Jiminny\\Component\\ES\\QueuePriorityEnum; /** /** * This class supplies a list of entities pending an update. * This class supplies a list of entities pending an update. public function select(): SelectionList public function select(): SelectionList { { $staleWorkEntityIds = $this->getStaleChunk(); $selectionList = new SelectionList(); $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $staleWorkEntityIds = $this->getStaleChunk(); if (count($staleWorkEntityIds) > 0) { if (count($staleWorkEntityIds) > 0) { return new SelectionList( /** priorityEntityIdList: $staleWorkEntityIds, * Stale chunks are treated as high priority isStaleChunkSelected: true, */ chunkSize: ChunkSize::getStaleChunkSize($this->updateTarget), $selectionList->markStale(); ); $selectionList->addEntityList(QueuePriorityEnum::HIGH, $staleWorkEntityIds); $selectionList->setChunkSize(ChunkSize::getStaleChunkSize($this->updateTarget)); return $selectionList; } } $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $selectionList->setChunkSize($mainChunkSize); $priorityEntityIdsList = $this->extractIdsFromSet( $priorityEntityIdsList = $this->extractIds(QueuePriorityEnum::HIGH, $mainChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, true), $selectionList->addEntityList(QueuePriorityEnum::HIGH, $priorityEntityIdsList); $mainChunkSize, ); $normalEntityIdsList = []; $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); if ($normalEntityChunkSize > 0) { if ($normalEntityChunkSize > 0) { $normalEntityIdsList = $this->extractIdsFromSet( $normalEntityIdsList = $this->extractIds(QueuePriorityEnum::NORMAL, $normalEntityChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, false), $selectionList->addEntityList(QueuePriorityEnum::NORMAL, $normalEntityIdsList); $normalEntityChunkSize ); } } return new SelectionList( return $selectionList; priorityEntityIdList: $priorityEntityIdsList, normalEntityIdList: $normalEntityIdsList, chunkSize: $mainChunkSize ); } } private function getStaleChunk(): array private function getStaleChunk(): array return []; return []; } } private function extractIds(QueuePriorityEnum $priority, int $chunkSize): array { return $this->extractIdsFromSet( AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, $priority), $chunkSize ); } } } app/Component/ES/AsyncUpdateElasticSearch.php +17-10Lines changed: 17 additions & 10 deletions Original file line numberOriginal file lineDiff line numberDiff line change * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * and other activity related data * and other activity related data */ */ public static function markEntityForUpdate(string $entityType, int $entityId, bool $withPriority = false): void public static function markEntityForUpdate( { string $entityType, $targetList = self::selectTargetList($entityType, $withPriority); int $entityId, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { $targetList = self::selectTargetList($entityType, $priority); Redis::sadd($targetList, $entityId); Redis::sadd($targetList, $entityId); Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ 'entityType' => $entityType, 'entityType' => $entityType, 'entityId' => $entityId, 'entityId' => $entityId, 'collectionKey' => $targetList, 'collectionKey' => $targetList, 'withPriority' => $withPriority, 'priority' => $priority->value, ]); ]); } } public static function bulkMarkEntitiesForUpdate( public static function bulkMarkEntitiesForUpdate( string $entityType, string $entityType, array $entityIds, array $entityIds, bool $withPriority = false QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { ): void { if (empty($entityIds)) { if (empty($entityIds)) { return; return; } } $targetList = self::selectTargetList($entityType, $withPriority); $targetList = self::selectTargetList($entityType, $priority); Redis::saddarray($targetList, $entityIds); Redis::saddarray($targetList, $entityIds); } } * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Takes priority into consideration. * Takes priority into consideration. */ */ public static function getEntitiesSourceList(string $updateTarget, $priority = false): string public static function getEntitiesSourceList( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { return self::selectTargetList($updateTarget, $priority); return self::selectTargetList($updateTarget, $priority); } } /** /** * Externally called helper methods * Externally called helper methods * - count and flush * - count and flush */ */ public static function getEntitiesListCount(string $updateTarget, $priority = false): int public static function getEntitiesListCount( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): int { $targetList = self::selectTargetList($updateTarget, $priority); $targetList = self::selectTargetList($updateTarget, $priority); return Redis::scard($targetList); return Redis::scard($targetList); app/Component/ES/QueuePriorityEnum.php +40Lines changed: 40 additions & 0 deletions Original file line numberOriginal file lineDiff line numberDiff line change <?php declare(strict_types=1); namespace Jiminny\\Component\\ES; use Jiminny\\Exceptions\\InvalidArgumentException; enum QueuePriorityEnum: string { case HIGH = 'high'; case NORMAL = 'normal'; case LOW = 'low'; public static function tryFromString(string $value): self { if (! self::isValid($value)) { throw new InvalidArgumentException( sprintf('Invalid queue priority \"%s\" selected', $value) ); } return self::tryFrom($value); } public static function isValid(string $value): bool { return self::tryFrom($value) !== null; } public function isLow(): bool { return $this === self::LOW; } public function isHigh(): bool { return $this === self::HIGH; } } app/Component/ES/UpdateProcessManager.php +12-9Lines changed: 12 additions & 9 deletions Original file line numberOriginal file lineDiff line numberDiff line change if ($selectionList->isEmpty()) { if ($selectionList->isEmpty()) { return false; return false; } } /** /** * A stale chunk will always be smaller than a regular chunk. * A stale chunk will always be smaller than a regular chunk. * That doesn't mean there aren't any other scheduled entities for processing * That doesn't mean there aren't any other scheduled entities for processing private function rescheduleThrottledEntities(SelectionList $selectionList): void private function rescheduleThrottledEntities(SelectionList $selectionList): void { { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $groups = $selectionList->getEntityListGroups(); $this->updateTarget, foreach ($groups as $eachGroup) { $selectionList->getNormalPriorityEntityId() $groupEntityIds = $selectionList->getEntityListItemsByGroup($eachGroup); ); if (! empty($groupEntityIds)) { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $this->updateTarget, entityType: $this->updateTarget, $selectionList->getHighPriorityEntityIds(), entityIds: $groupEntityIds, true priority: QueuePriorityEnum::tryFromString($eachGroup) ); ); } } } } } } app/Console/Commands/Elasticsearch/AsyncUpdateEsEntities.php +9-3Lines changed: 9 additions & 3 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Illuminate\\Support\\Str; use Illuminate\\Support\\Str; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Component\\ES\\UpdateProcessManager; use Jiminny\\Component\\ES\\UpdateProcessManager; use Jiminny\\Exceptions\\InvalidArgumentException; use Jiminny\\Exceptions\\InvalidArgumentException; use Jiminny\\Traits\\GracefullyStoppable; use Jiminny\\Traits\\GracefullyStoppable; Redis::set($gaugeLockName, true); Redis::set($gaugeLockName, true); Redis::expire($gaugeLockName, 60); Redis::expire($gaugeLockName, 60); $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::HIGH), ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update', $updateTarget), stat: sprintf('jiminny.%s-for-update', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::NORMAL), ); ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), stat: sprintf('jiminny.%s-for-update-low', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, true), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::LOW), ); ); } } app/Console/Commands/Elasticsearch/ResetAsyncElasticSearchCommand.php +5-1Lines changed: 5 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder; use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder; use Jiminny\\Component\\ES\\Processor\\Traits\\ValidateUpdateTargetTrait; use Jiminny\\Component\\ES\\Processor\\Traits\\ValidateUpdateTargetTrait; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Component\\ES\\Repositories\\EsResetRepositoryInterface; use Jiminny\\Component\\ES\\Repositories\\EsResetRepositoryInterface; use Jiminny\\Exceptions\\InvalidArgumentException; use Jiminny\\Exceptions\\InvalidArgumentException; use Jiminny\\Traits\\GracefullyStoppable; use Jiminny\\Traits\\GracefullyStoppable; private function getRemainingScheduledEntities(bool $printStatus = false): int private function getRemainingScheduledEntities(bool $printStatus = false): int { { $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget, true); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount( $this->updateTarget, QueuePriorityEnum::HIGH ); if ($printStatus) { if ($printStatus) { $this->line( $this->line(","depth":21,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"You said","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app/Component/ES/Listeners/UpdateMultipleTargetsListener.php","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"+2-1Lines changed: 2 additions & 1 deletion","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\\Component\\ES\\Listeners;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"namespace Jiminny\\Component\\ES\\Listeners;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\QueuePriorityEnum;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Contracts\\ES\\Events\\UpdateMultipleEntities;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Contracts\\ES\\Events\\UpdateMultipleEntities;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Psr\\Log\\LoggerInterface;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Psr\\Log\\LoggerInterface;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getUpdateTargetValue(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getUpdateTargetValue(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getEntities(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getEntities(),","depth":23,"bounds":{"left":0.20578457,"top":0.0,"width":0.052526597,"height":0.016360734},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->isPriority()","depth":23,"bounds":{"left":0.20578457,"top":0.0,"width":0.046708778,"height":0.016360734},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL,","depth":23,"bounds":{"left":0.20578457,"top":0.0,"width":0.11702128,"height":0.035514764},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":");","depth":23,"bounds":{"left":0.20578457,"top":0.0,"width":0.0033244682,"height":0.016360734},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":");","depth":23,"bounds":{"left":0.20578457,"top":0.003990423,"width":0.0033244682,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"bounds":{"left":0.20578457,"top":0.023144454,"width":0.0019946808,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"bounds":{"left":0.20578457,"top":0.042298485,"width":0.0019946808,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"bounds":{"left":0.20578457,"top":0.061452515,"width":0.0019946808,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"bounds":{"left":0.20578457,"top":0.08060654,"width":0.0019946808,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app/Component/ES/Listeners/UpdateSingleTargetListener.php","depth":23,"bounds":{"left":0.20578457,"top":0.09976058,"width":0.07762633,"height":0.035514764},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"+9-1Lines changed: 9 additions & 1 deletion","depth":23,"bounds":{"left":0.20578457,"top":0.15722266,"width":0.104222074,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Actions\\TrackElasticSearchOperations;","depth":23,"bounds":{"left":0.20578457,"top":0.19553073,"width":0.13480718,"height":0.073822826},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Actions\\TrackElasticSearchOperations;","depth":23,"bounds":{"left":0.20578457,"top":0.27214685,"width":0.13480718,"height":0.054668795},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch;","depth":23,"bounds":{"left":0.20578457,"top":0.32960895,"width":0.13380983,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch;","depth":23,"bounds":{"left":0.20578457,"top":0.34876296,"width":0.13380983,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder;","depth":23,"bounds":{"left":0.20578457,"top":0.367917,"width":0.1306516,"height":0.035514764},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder;","depth":23,"bounds":{"left":0.20578457,"top":0.40622506,"width":0.1306516,"height":0.035514764},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\QueuePriorityEnum;","depth":23,"bounds":{"left":0.20578457,"top":0.4828412,"width":0.115359046,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Contracts\\ES\\Events\\UpdateSingleEntity;","depth":23,"bounds":{"left":0.20578457,"top":0.5019952,"width":0.12732713,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Contracts\\ES\\Events\\UpdateSingleEntity;","depth":23,"bounds":{"left":0.20578457,"top":0.5211492,"width":0.12732713,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Psr\\Log\\LoggerInterface;","depth":23,"bounds":{"left":0.20578457,"top":0.5403033,"width":0.07047872,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Psr\\Log\\LoggerInterface;","depth":23,"bounds":{"left":0.20578457,"top":0.5594573,"width":0.07047872,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"'entityId' => $event->getEntityId(),","depth":23,"bounds":{"left":0.20578457,"top":0.6169194,"width":0.08228058,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"'entityId' => $event->getEntityId(),","depth":23,"bounds":{"left":0.20578457,"top":0.6360734,"width":0.08228058,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"]);","depth":23,"bounds":{"left":0.20578457,"top":0.6552275,"width":0.0051529254,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"]);","depth":23,"bounds":{"left":0.20578457,"top":0.6743815,"width":0.0051529254,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/**","depth":23,"bounds":{"left":0.20578457,"top":0.7701516,"width":0.0066489363,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* @important:","depth":23,"bounds":{"left":0.20578457,"top":0.8276137,"width":0.03374335,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* Synchronous event should eventually be deprecated.","depth":23,"bounds":{"left":0.20578457,"top":0.8850758,"width":0.13131648,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* Instant write operations are blocking and should be used sparingly.","depth":23,"bounds":{"left":0.20578457,"top":0.9425379,"width":0.12732713,"height":0.035514764},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* It is much better in terms of performance to write 100 or 1000 documents at once,","depth":23,"bounds":{"left":0.20578457,"top":1.0,"width":0.13314494,"height":-0.019154072},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* and have one blocking reindex operation, instead of writing 10 documents synchronously.","depth":23,"bounds":{"left":0.20578457,"top":1.0,"width":0.12865691,"height":-0.09577012},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"*/","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"if ($event->isSyncEvent()) {","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"if ($event->isSyncEvent()) {","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$this->handleSyncEvent($event);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$this->handleSyncEvent($event);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AsyncUpdateElasticSearch::markEntityForUpdate(","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AsyncUpdateElasticSearch::markEntityForUpdate(","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getUpdateTargetValue(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getUpdateTargetValue(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getEntityId(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getEntityId(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->isPriority()","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL,","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":");","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":");","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app/Component/ES/Processor/Actions/UpsertDocumentsAction.php","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"+2-1Lines changed: 2 additions & 1 deletion","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Processor\\DTOs\\SimpleCollection;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\DTOs\\SimpleCollection;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\ResponseEvaluator;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\ResponseEvaluator;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\QueuePriorityEnum;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Exceptions\\InvalidDataException;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Exceptions\\InvalidDataException;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Sentry\\Laravel\\Facade as Sentry;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Sentry\\Laravel\\Facade as Sentry;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AsyncUpdateElasticSearch::markEntityForUpdate(","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AsyncUpdateElasticSearch::markEntityForUpdate(","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"entityType: $this->updateTarget,","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"entityType: $this->updateTarget,","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"entityId: (int) $document->getId(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"entityId: (int) $document->getId(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"withPriority: true","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"priority: QueuePriorityEnum::HIGH,","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":");","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":");","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app/Component/ES/Processor/DTOs/SelectionList.php","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"+54-17Lines changed: 54 additions & 17 deletions","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Original file line numberOriginal file lineDiff line numberDiff line change","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"namespace Jiminny\\Component\\ES\\Processor\\DTOs;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"namespace Jiminny\\Component\\ES\\Processor\\DTOs;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\QueuePriorityEnum;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/**","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/**","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* A very basic and simple collection of entity IDs.","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* A very basic and simple collection of entity IDs.","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"*/","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"*/","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"class SelectionList","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"class SelectionList","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function __construct(","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private const int DEFAULT_CHUNK = 200;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private readonly array $priorityEntityIdList = [],","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private readonly array $normalEntityIdList = [],","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private int $chunkSize = self::DEFAULT_CHUNK;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private readonly bool $isStaleChunkSelected = false,","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private bool $isStaleChunkSelected = false;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private readonly int $chunkSize = 200,","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private array $selectedEntityIds = [];","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":") {","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"// Do nothing","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function setChunkSize(int $chunkSize): void","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$this->chunkSize = $chunkSize;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function getAllIds(): array","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function markStale(): void","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"return array_merge($this->priorityEntityIdList, $this->normalEntityIdList);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$this->isStaleChunkSelected = true;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function count(): int","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function addEntityList(string|QueuePriorityEnum $priority, array $entityIds): void","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"return count($this->priorityEntityIdList) + count($this->normalEntityIdList);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$priorityKey = $this->normalisePriority($priority);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"if (! array_key_exists($priorityKey, $this->selectedEntityIds)) {","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$this->selectedEntityIds[$priorityKey] = [];","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$this->selectedEntityIds[$priorityKey] = array_merge($this->selectedEntityIds[$priorityKey], $entityIds);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function isEmpty(): bool","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/**","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* @return string[]","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"*/","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function getEntityListGroups(): array","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"return empty($this->priorityEntityIdList) && empty($this->normalEntityIdList);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"return array_keys($this->selectedEntityIds);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function getHighPriorityEntityIds(): array","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function getEntityListItemsByGroup(string|QueuePriorityEnum $priority): array","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"return $this->priorityEntityIdList;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$priorityKey = $this->normalisePriority($priority);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"return $this->selectedEntityIds[$priorityKey] ?? [];","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function getNormalPriorityEntityId(): array","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function getAllIds(): array","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"return $this->normalEntityIdList;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$allIds = [];","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"foreach ($this->selectedEntityIds as $entityIds) {","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$allIds = array_merge($allIds, $entityIds);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"return $allIds;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"}]...
|
5552443098384522644
|
-1144453838252598132
|
click
|
accessibility
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
Close tab
New Tab
Customize sidebar
Close Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
AI Chat settings
Close
WORK, Google Account: [EMAIL]
Main menu
New chat
Gemini
New Chat
Open menu for conversation actions.
Conversation with Gemini
Conversation with Gemini
Show the uploaded image in a lightbox
Copy prompt
You said Make a PR of changes Find potential issues and bottlenecks
You said
Make a PR of changes Find potential issues and bottlenecks
Listen
Show thinking
Gemini said
Gemini said
I can see you've uploaded a screenshot of a code diff, likely from a version control system given the red and green highlights. I would love to help you review the changes, spot bottlenecks, and help you draft a Pull Request.
However,
the image resolution is far too low for me to read.
It appears to be a completely zoomed-out view where the code has been reduced to tiny, illegible pixels. Because of this, I cannot extract any text or logic to analyze.
How You Can Share the Code
How You Can Share the Code
To help me review your code effectively, please try one of the following:
Paste the text directly:
Copy the specific code blocks (both the old and new versions if possible) and paste them directly into our chat.
Upload the files:
If the changes are extensive, you can upload the raw text or code files.
Take high-resolution screenshots:
If you must use images, take closer, readable screenshots of the specific functions or methods you want me to review.
Once you provide the readable code, I can dive right in to identify potential bugs, assess performance bottlenecks, and help you summarize the changes for your PR!
Good response
Bad response
Share & export
Copy
Show more options
Copy prompt
Edit
You said app/Component/ES/Listeners/UpdateMultipleTargetsListener.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\Component\ES\Listeners; namespace Jiminny\Component\ES\Listeners; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Contracts\ES\Events\UpdateMultipleEntities; use Jiminny\Contracts\ES\Events\UpdateMultipleEntities; use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface; AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntities(), $event->getEntities(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } } } app/Component/ES/Listeners/UpdateSingleTargetListener.php +9-1Lines changed: 9 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Actions\TrackElasticSearchOperations; use Jiminny\Component\ES\Actions\TrackElasticSearchOperations; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Contracts\ES\Events\UpdateSingleEntity; use Jiminny\Contracts\ES\Events\UpdateSingleEntity; use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface; 'entityId' => $event->getEntityId(), 'entityId' => $event->getEntityId(), ]); ]); /** * @important: * Synchronous event should eventually be deprecated. * Instant write operations are blocking and should be used sparingly. * It is much better in terms of performance to write 100 or 1000 documents at once, * and have one blocking reindex operation, instead of writing 10 documents synchronously. */ if ($event->isSyncEvent()) { if ($event->isSyncEvent()) { $this->handleSyncEvent($event); $this->handleSyncEvent($event); AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntityId(), $event->getEntityId(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } app/Component/ES/Processor/Actions/UpsertDocumentsAction.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SimpleCollection; use Jiminny\Component\ES\Processor\DTOs\SimpleCollection; use Jiminny\Component\ES\Processor\ResponseEvaluator; use Jiminny\Component\ES\Processor\ResponseEvaluator; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Exceptions\InvalidDataException; use Jiminny\Exceptions\InvalidDataException; use Sentry\Laravel\Facade as Sentry; use Sentry\Laravel\Facade as Sentry; AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( entityType: $this->updateTarget, entityType: $this->updateTarget, entityId: (int) $document->getId(), entityId: (int) $document->getId(), withPriority: true priority: QueuePriorityEnum::HIGH, ); ); } } app/Component/ES/Processor/DTOs/SelectionList.php +54-17Lines changed: 54 additions & 17 deletions Original file line numberOriginal file lineDiff line numberDiff line change namespace Jiminny\Component\ES\Processor\DTOs; namespace Jiminny\Component\ES\Processor\DTOs; use Jiminny\Component\ES\QueuePriorityEnum; /** /** * A very basic and simple collection of entity IDs. * A very basic and simple collection of entity IDs. */ */ class SelectionList class SelectionList { { public function __construct( private const int DEFAULT_CHUNK = 200; private readonly array $priorityEntityIdList = [], private readonly array $normalEntityIdList = [], private int $chunkSize = self::DEFAULT_CHUNK; private readonly bool $isStaleChunkSelected = false, private bool $isStaleChunkSelected = false; private readonly int $chunkSize = 200, private array $selectedEntityIds = []; ) { // Do nothing public function setChunkSize(int $chunkSize): void { $this->chunkSize = $chunkSize; } } public function getAllIds(): array public function markStale(): void { { return array_merge($this->priorityEntityIdList, $this->normalEntityIdList); $this->isStaleChunkSelected = true; } } public function count(): int public function addEntityList(string|QueuePriorityEnum $priority, array $entityIds): void { { return count($this->priorityEntityIdList) + count($this->normalEntityIdList); $priorityKey = $this->normalisePriority($priority); if (! array_key_exists($priorityKey, $this->selectedEntityIds)) { $this->selectedEntityIds[$priorityKey] = []; } $this->selectedEntityIds[$priorityKey] = array_merge($this->selectedEntityIds[$priorityKey], $entityIds); } } public function isEmpty(): bool /** * @return string[] */ public function getEntityListGroups(): array { { return empty($this->priorityEntityIdList) && empty($this->normalEntityIdList); return array_keys($this->selectedEntityIds); } } public function getHighPriorityEntityIds(): array public function getEntityListItemsByGroup(string|QueuePriorityEnum $priority): array { { return $this->priorityEntityIdList; $priorityKey = $this->normalisePriority($priority); return $this->selectedEntityIds[$priorityKey] ?? []; } } public function getNormalPriorityEntityId(): array public function getAllIds(): array { { return $this->normalEntityIdList; $allIds = []; foreach ($this->selectedEntityIds as $entityIds) { $allIds = array_merge($allIds, $entityIds); } return $allIds; } public function count(): int { return array_sum( array_map('count', $this->selectedEntityIds) ); } public function isEmpty(): bool { return $this->count() === 0; } } public function isStaleChunkSelected(): bool public function isStaleChunkSelected(): bool { { return $this->count() >= $this->chunkSize; return $this->count() >= $this->chunkSize; } } private function normalisePriority(string|QueuePriorityEnum $priority): string { return $priority instanceof QueuePriorityEnum ? $priority->value : $priority; } } } app/Component/ES/Processor/Traits/SelectEntityListTrait.php +27-4Lines changed: 27 additions & 4 deletions Original file line numberOriginal file lineDiff line numberDiff line change use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; /** /** * Build the correct source list name for the type of entity and priority * Build the correct source list name for the type of entity and priority */ */ trait SelectEntityListTrait trait SelectEntityListTrait { { /** * Highest priority queue for data requiring near-instant availability. * Very few entities should be added here, only when absolutely necessary. */ private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; /** * Normal priority queue for normal application operations. * Almost all update events should pass through this queue */ private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; protected static function selectTargetList(string $entityType, bool $withPriority = false): string /** { * Nonblocking low priority queue. This queue will be consumed only when there is nothing * with higher priority. * * This queue will be used for operations such as es:reset-async */ private const string ENTITIES_LOW_PRIORITIES_LIST = '%s-for-update-low'; protected static function selectTargetList( string $entityType, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { if (! in_array($entityType, UpdateTarget::allowedTargets())) { if (! in_array($entityType, UpdateTarget::allowedTargets())) { throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); } } if ($withPriority) { if ($priority->isHigh()) { Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); } } if ($priority->isLow()) { return sprintf(self::ENTITIES_LOW_PRIORITIES_LIST, $entityType); } return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); } } } } app/Component/ES/Processor/TargetEntitiesSelector.php +26-21Lines changed: 26 additions & 21 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SelectionList; use Jiminny\Component\ES\Processor\DTOs\SelectionList; use Jiminny\Component\ES\Processor\Traits\ExtractIdsTrait; use Jiminny\Component\ES\Processor\Traits\ExtractIdsTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\QueuePriorityEnum; /** /** * This class supplies a list of entities pending an update. * This class supplies a list of entities pending an update. public function select(): SelectionList public function select(): SelectionList { { $staleWorkEntityIds = $this->getStaleChunk(); $selectionList = new SelectionList(); $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $staleWorkEntityIds = $this->getStaleChunk(); if (count($staleWorkEntityIds) > 0) { if (count($staleWorkEntityIds) > 0) { return new SelectionList( /** priorityEntityIdList: $staleWorkEntityIds, * Stale chunks are treated as high priority isStaleChunkSelected: true, */ chunkSize: ChunkSize::getStaleChunkSize($this->updateTarget), $selectionList->markStale(); ); $selectionList->addEntityList(QueuePriorityEnum::HIGH, $staleWorkEntityIds); $selectionList->setChunkSize(ChunkSize::getStaleChunkSize($this->updateTarget)); return $selectionList; } } $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $selectionList->setChunkSize($mainChunkSize); $priorityEntityIdsList = $this->extractIdsFromSet( $priorityEntityIdsList = $this->extractIds(QueuePriorityEnum::HIGH, $mainChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, true), $selectionList->addEntityList(QueuePriorityEnum::HIGH, $priorityEntityIdsList); $mainChunkSize, ); $normalEntityIdsList = []; $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); if ($normalEntityChunkSize > 0) { if ($normalEntityChunkSize > 0) { $normalEntityIdsList = $this->extractIdsFromSet( $normalEntityIdsList = $this->extractIds(QueuePriorityEnum::NORMAL, $normalEntityChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, false), $selectionList->addEntityList(QueuePriorityEnum::NORMAL, $normalEntityIdsList); $normalEntityChunkSize ); } } return new SelectionList( return $selectionList; priorityEntityIdList: $priorityEntityIdsList, normalEntityIdList: $normalEntityIdsList, chunkSize: $mainChunkSize ); } } private function getStaleChunk(): array private function getStaleChunk(): array return []; return []; } } private function extractIds(QueuePriorityEnum $priority, int $chunkSize): array { return $this->extractIdsFromSet( AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, $priority), $chunkSize ); } } } app/Component/ES/AsyncUpdateElasticSearch.php +17-10Lines changed: 17 additions & 10 deletions Original file line numberOriginal file lineDiff line numberDiff line change * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * and other activity related data * and other activity related data */ */ public static function markEntityForUpdate(string $entityType, int $entityId, bool $withPriority = false): void public static function markEntityForUpdate( { string $entityType, $targetList = self::selectTargetList($entityType, $withPriority); int $entityId, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { $targetList = self::selectTargetList($entityType, $priority); Redis::sadd($targetList, $entityId); Redis::sadd($targetList, $entityId); Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ 'entityType' => $entityType, 'entityType' => $entityType, 'entityId' => $entityId, 'entityId' => $entityId, 'collectionKey' => $targetList, 'collectionKey' => $targetList, 'withPriority' => $withPriority, 'priority' => $priority->value, ]); ]); } } public static function bulkMarkEntitiesForUpdate( public static function bulkMarkEntitiesForUpdate( string $entityType, string $entityType, array $entityIds, array $entityIds, bool $withPriority = false QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { ): void { if (empty($entityIds)) { if (empty($entityIds)) { return; return; } } $targetList = self::selectTargetList($entityType, $withPriority); $targetList = self::selectTargetList($entityType, $priority); Redis::saddarray($targetList, $entityIds); Redis::saddarray($targetList, $entityIds); } } * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Takes priority into consideration. * Takes priority into consideration. */ */ public static function getEntitiesSourceList(string $updateTarget, $priority = false): string public static function getEntitiesSourceList( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { return self::selectTargetList($updateTarget, $priority); return self::selectTargetList($updateTarget, $priority); } } /** /** * Externally called helper methods * Externally called helper methods * - count and flush * - count and flush */ */ public static function getEntitiesListCount(string $updateTarget, $priority = false): int public static function getEntitiesListCount( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): int { $targetList = self::selectTargetList($updateTarget, $priority); $targetList = self::selectTargetList($updateTarget, $priority); return Redis::scard($targetList); return Redis::scard($targetList); app/Component/ES/QueuePriorityEnum.php +40Lines changed: 40 additions & 0 deletions Original file line numberOriginal file lineDiff line numberDiff line change <?php declare(strict_types=1); namespace Jiminny\Component\ES; use Jiminny\Exceptions\InvalidArgumentException; enum QueuePriorityEnum: string { case HIGH = 'high'; case NORMAL = 'normal'; case LOW = 'low'; public static function tryFromString(string $value): self { if (! self::isValid($value)) { throw new InvalidArgumentException( sprintf('Invalid queue priority "%s" selected', $value) ); } return self::tryFrom($value); } public static function isValid(string $value): bool { return self::tryFrom($value) !== null; } public function isLow(): bool { return $this === self::LOW; } public function isHigh(): bool { return $this === self::HIGH; } } app/Component/ES/UpdateProcessManager.php +12-9Lines changed: 12 additions & 9 deletions Original file line numberOriginal file lineDiff line numberDiff line change if ($selectionList->isEmpty()) { if ($selectionList->isEmpty()) { return false; return false; } } /** /** * A stale chunk will always be smaller than a regular chunk. * A stale chunk will always be smaller than a regular chunk. * That doesn't mean there aren't any other scheduled entities for processing * That doesn't mean there aren't any other scheduled entities for processing private function rescheduleThrottledEntities(SelectionList $selectionList): void private function rescheduleThrottledEntities(SelectionList $selectionList): void { { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $groups = $selectionList->getEntityListGroups(); $this->updateTarget, foreach ($groups as $eachGroup) { $selectionList->getNormalPriorityEntityId() $groupEntityIds = $selectionList->getEntityListItemsByGroup($eachGroup); ); if (! empty($groupEntityIds)) { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $this->updateTarget, entityType: $this->updateTarget, $selectionList->getHighPriorityEntityIds(), entityIds: $groupEntityIds, true priority: QueuePriorityEnum::tryFromString($eachGroup) ); ); } } } } } } app/Console/Commands/Elasticsearch/AsyncUpdateEsEntities.php +9-3Lines changed: 9 additions & 3 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Illuminate\Support\Str; use Illuminate\Support\Str; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Component\ES\UpdateProcessManager; use Jiminny\Component\ES\UpdateProcessManager; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Traits\GracefullyStoppable; use Jiminny\Traits\GracefullyStoppable; Redis::set($gaugeLockName, true); Redis::set($gaugeLockName, true); Redis::expire($gaugeLockName, 60); Redis::expire($gaugeLockName, 60); $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::HIGH), ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update', $updateTarget), stat: sprintf('jiminny.%s-for-update', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::NORMAL), ); ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), stat: sprintf('jiminny.%s-for-update-low', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, true), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::LOW), ); ); } } app/Console/Commands/Elasticsearch/ResetAsyncElasticSearchCommand.php +5-1Lines changed: 5 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\Traits\ValidateUpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\ValidateUpdateTargetTrait; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Component\ES\Repositories\EsResetRepositoryInterface; use Jiminny\Component\ES\Repositories\EsResetRepositoryInterface; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Traits\GracefullyStoppable; use Jiminny\Traits\GracefullyStoppable; private function getRemainingScheduledEntities(bool $printStatus = false): int private function getRemainingScheduledEntities(bool $printStatus = false): int { { $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget, true); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount( $this->updateTarget, QueuePriorityEnum::HIGH ); if ($printStatus) { if ($printStatus) { $this->line( $this->line(
You said
app/Component/ES/Listeners/UpdateMultipleTargetsListener.php
+2-1Lines changed: 2 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\Component\ES\Listeners;
namespace Jiminny\Component\ES\Listeners;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\QueuePriorityEnum;
use Jiminny\Contracts\ES\Events\UpdateMultipleEntities;
use Jiminny\Contracts\ES\Events\UpdateMultipleEntities;
use Psr\Log\LoggerInterface;
use Psr\Log\LoggerInterface;
AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(
AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(
$event->getUpdateTargetValue(),
$event->getUpdateTargetValue(),
$event->getEntities(),
$event->getEntities(),
$event->isPriority()
$event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL,
);
);
}
}
}
}
app/Component/ES/Listeners/UpdateSingleTargetListener.php
+9-1Lines changed: 9 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Actions\TrackElasticSearchOperations;
use Jiminny\Component\ES\Actions\TrackElasticSearchOperations;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\Processor\EntityQueryBuilder;
use Jiminny\Component\ES\Processor\EntityQueryBuilder;
use Jiminny\Component\ES\QueuePriorityEnum;
use Jiminny\Contracts\ES\Events\UpdateSingleEntity;
use Jiminny\Contracts\ES\Events\UpdateSingleEntity;
use Psr\Log\LoggerInterface;
use Psr\Log\LoggerInterface;
'entityId' => $event->getEntityId(),
'entityId' => $event->getEntityId(),
]);
]);
/**
* @important:
* Synchronous event should eventually be deprecated.
* Instant write operations are blocking and should be used sparingly.
* It is much better in terms of performance to write 100 or 1000 documents at once,
* and have one blocking reindex operation, instead of writing 10 documents synchronously.
*/
if ($event->isSyncEvent()) {
if ($event->isSyncEvent()) {
$this->handleSyncEvent($event);
$this->handleSyncEvent($event);
AsyncUpdateElasticSearch::markEntityForUpdate(
AsyncUpdateElasticSearch::markEntityForUpdate(
$event->getUpdateTargetValue(),
$event->getUpdateTargetValue(),
$event->getEntityId(),
$event->getEntityId(),
$event->isPriority()
$event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL,
);
);
}
}
app/Component/ES/Processor/Actions/UpsertDocumentsAction.php
+2-1Lines changed: 2 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SimpleCollection;
use Jiminny\Component\ES\Processor\DTOs\SimpleCollection;
use Jiminny\Component\ES\Processor\ResponseEvaluator;
use Jiminny\Component\ES\Processor\ResponseEvaluator;
use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait;
use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait;
use Jiminny\Component\ES\QueuePriorityEnum;
use Jiminny\Exceptions\InvalidDataException;
use Jiminny\Exceptions\InvalidDataException;
use Sentry\Laravel\Facade as Sentry;
use Sentry\Laravel\Facade as Sentry;
AsyncUpdateElasticSearch::markEntityForUpdate(
AsyncUpdateElasticSearch::markEntityForUpdate(
entityType: $this->updateTarget,
entityType: $this->updateTarget,
entityId: (int) $document->getId(),
entityId: (int) $document->getId(),
withPriority: true
priority: QueuePriorityEnum::HIGH,
);
);
}
}
app/Component/ES/Processor/DTOs/SelectionList.php
+54-17Lines changed: 54 additions & 17 deletions
Original file line numberOriginal file lineDiff line numberDiff line change
namespace Jiminny\Component\ES\Processor\DTOs;
namespace Jiminny\Component\ES\Processor\DTOs;
use Jiminny\Component\ES\QueuePriorityEnum;
/**
/**
* A very basic and simple collection of entity IDs.
* A very basic and simple collection of entity IDs.
*/
*/
class SelectionList
class SelectionList
{
{
public function __construct(
private const int DEFAULT_CHUNK = 200;
private readonly array $priorityEntityIdList = [],
private readonly array $normalEntityIdList = [],
private int $chunkSize = self::DEFAULT_CHUNK;
private readonly bool $isStaleChunkSelected = false,
private bool $isStaleChunkSelected = false;
private readonly int $chunkSize = 200,
private array $selectedEntityIds = [];
) {
// Do nothing
public function setChunkSize(int $chunkSize): void
{
$this->chunkSize = $chunkSize;
}
}
public function getAllIds(): array
public function markStale(): void
{
{
return array_merge($this->priorityEntityIdList, $this->normalEntityIdList);
$this->isStaleChunkSelected = true;
}
}
public function count(): int
public function addEntityList(string|QueuePriorityEnum $priority, array $entityIds): void
{
{
return count($this->priorityEntityIdList) + count($this->normalEntityIdList);
$priorityKey = $this->normalisePriority($priority);
if (! array_key_exists($priorityKey, $this->selectedEntityIds)) {
$this->selectedEntityIds[$priorityKey] = [];
}
$this->selectedEntityIds[$priorityKey] = array_merge($this->selectedEntityIds[$priorityKey], $entityIds);
}
}
public function isEmpty(): bool
/**
* @return string[]
*/
public function getEntityListGroups(): array
{
{
return empty($this->priorityEntityIdList) && empty($this->normalEntityIdList);
return array_keys($this->selectedEntityIds);
}
}
public function getHighPriorityEntityIds(): array
public function getEntityListItemsByGroup(string|QueuePriorityEnum $priority): array
{
{
return $this->priorityEntityIdList;
$priorityKey = $this->normalisePriority($priority);
return $this->selectedEntityIds[$priorityKey] ?? [];
}
}
public function getNormalPriorityEntityId(): array
public function getAllIds(): array
{
{
return $this->normalEntityIdList;
$allIds = [];
foreach ($this->selectedEntityIds as $entityIds) {
$allIds = array_merge($allIds, $entityIds);
}
return $allIds;...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
55699
|
1934
|
1
|
2026-05-19T06:42:49.357959+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779172969357_m1.jpg...
|
Firefox
|
JY-20808 low priority indexing queue by Vasil-Jimi JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app — Work...
|
1
|
github.com/jiminny/app/pull/12082/changes#diff-49a github.com/jiminny/app/pull/12082/changes#diff-49a79d99c97caf7fc27ecb1dbacab5a29d871822caa0db0c71e94957c28c87af...
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
Close tab
New Tab
Customize sidebar
Close Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
AI Chat settings
Close
WORK, Google Account: [EMAIL]
Main menu
New chat
Gemini
New Chat
Open menu for conversation actions.
Conversation with Gemini
Conversation with Gemini
Show the uploaded image in a lightbox
Copy prompt
You said Make a PR of changes Find potential issues and bottlenecks
You said
Make a PR of changes Find potential issues and bottlenecks
Listen
Show thinking
Gemini said
Gemini said
I can see you've uploaded a screenshot of a code diff, likely from a version control system given the red and green highlights. I would love to help you review the changes, spot bottlenecks, and help you draft a Pull Request.
However,
the image resolution is far too low for me to read.
It appears to be a completely zoomed-out view where the code has been reduced to tiny, illegible pixels. Because of this, I cannot extract any text or logic to analyze.
How You Can Share the Code
How You Can Share the Code
To help me review your code effectively, please try one of the following:
Paste the text directly:
Copy the specific code blocks (both the old and new versions if possible) and paste them directly into our chat.
Upload the files:
If the changes are extensive, you can upload the raw text or code files.
Take high-resolution screenshots:
If you must use images, take closer, readable screenshots of the specific functions or methods you want me to review.
Once you provide the readable code, I can dive right in to identify potential bugs, assess performance bottlenecks, and help you summarize the changes for your PR!
Good response
Bad response
Share & export
Copy
Show more options
Copy prompt
Edit
You said app/Component/ES/Listeners/UpdateMultipleTargetsListener.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\Component\ES\Listeners; namespace Jiminny\Component\ES\Listeners; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Contracts\ES\Events\UpdateMultipleEntities; use Jiminny\Contracts\ES\Events\UpdateMultipleEntities; use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface; AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntities(), $event->getEntities(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } } } app/Component/ES/Listeners/UpdateSingleTargetListener.php +9-1Lines changed: 9 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Actions\TrackElasticSearchOperations; use Jiminny\Component\ES\Actions\TrackElasticSearchOperations; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Contracts\ES\Events\UpdateSingleEntity; use Jiminny\Contracts\ES\Events\UpdateSingleEntity; use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface; 'entityId' => $event->getEntityId(), 'entityId' => $event->getEntityId(), ]); ]); /** * @important: * Synchronous event should eventually be deprecated. * Instant write operations are blocking and should be used sparingly. * It is much better in terms of performance to write 100 or 1000 documents at once, * and have one blocking reindex operation, instead of writing 10 documents synchronously. */ if ($event->isSyncEvent()) { if ($event->isSyncEvent()) { $this->handleSyncEvent($event); $this->handleSyncEvent($event); AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntityId(), $event->getEntityId(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } app/Component/ES/Processor/Actions/UpsertDocumentsAction.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SimpleCollection; use Jiminny\Component\ES\Processor\DTOs\SimpleCollection; use Jiminny\Component\ES\Processor\ResponseEvaluator; use Jiminny\Component\ES\Processor\ResponseEvaluator; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Exceptions\InvalidDataException; use Jiminny\Exceptions\InvalidDataException; use Sentry\Laravel\Facade as Sentry; use Sentry\Laravel\Facade as Sentry; AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( entityType: $this->updateTarget, entityType: $this->updateTarget, entityId: (int) $document->getId(), entityId: (int) $document->getId(), withPriority: true priority: QueuePriorityEnum::HIGH, ); ); } } app/Component/ES/Processor/DTOs/SelectionList.php +54-17Lines changed: 54 additions & 17 deletions Original file line numberOriginal file lineDiff line numberDiff line change namespace Jiminny\Component\ES\Processor\DTOs; namespace Jiminny\Component\ES\Processor\DTOs; use Jiminny\Component\ES\QueuePriorityEnum; /** /** * A very basic and simple collection of entity IDs. * A very basic and simple collection of entity IDs. */ */ class SelectionList class SelectionList { { public function __construct( private const int DEFAULT_CHUNK = 200; private readonly array $priorityEntityIdList = [], private readonly array $normalEntityIdList = [], private int $chunkSize = self::DEFAULT_CHUNK; private readonly bool $isStaleChunkSelected = false, private bool $isStaleChunkSelected = false; private readonly int $chunkSize = 200, private array $selectedEntityIds = []; ) { // Do nothing public function setChunkSize(int $chunkSize): void { $this->chunkSize = $chunkSize; } } public function getAllIds(): array public function markStale(): void { { return array_merge($this->priorityEntityIdList, $this->normalEntityIdList); $this->isStaleChunkSelected = true; } } public function count(): int public function addEntityList(string|QueuePriorityEnum $priority, array $entityIds): void { { return count($this->priorityEntityIdList) + count($this->normalEntityIdList); $priorityKey = $this->normalisePriority($priority); if (! array_key_exists($priorityKey, $this->selectedEntityIds)) { $this->selectedEntityIds[$priorityKey] = []; } $this->selectedEntityIds[$priorityKey] = array_merge($this->selectedEntityIds[$priorityKey], $entityIds); } } public function isEmpty(): bool /** * @return string[] */ public function getEntityListGroups(): array { { return empty($this->priorityEntityIdList) && empty($this->normalEntityIdList); return array_keys($this->selectedEntityIds); } } public function getHighPriorityEntityIds(): array public function getEntityListItemsByGroup(string|QueuePriorityEnum $priority): array { { return $this->priorityEntityIdList; $priorityKey = $this->normalisePriority($priority); return $this->selectedEntityIds[$priorityKey] ?? []; } } public function getNormalPriorityEntityId(): array public function getAllIds(): array { { return $this->normalEntityIdList; $allIds = []; foreach ($this->selectedEntityIds as $entityIds) { $allIds = array_merge($allIds, $entityIds); } return $allIds; } public function count(): int { return array_sum( array_map('count', $this->selectedEntityIds) ); } public function isEmpty(): bool { return $this->count() === 0; } } public function isStaleChunkSelected(): bool public function isStaleChunkSelected(): bool { { return $this->count() >= $this->chunkSize; return $this->count() >= $this->chunkSize; } } private function normalisePriority(string|QueuePriorityEnum $priority): string { return $priority instanceof QueuePriorityEnum ? $priority->value : $priority; } } } app/Component/ES/Processor/Traits/SelectEntityListTrait.php +27-4Lines changed: 27 additions & 4 deletions Original file line numberOriginal file lineDiff line numberDiff line change use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; /** /** * Build the correct source list name for the type of entity and priority * Build the correct source list name for the type of entity and priority */ */ trait SelectEntityListTrait trait SelectEntityListTrait { { /** * Highest priority queue for data requiring near-instant availability. * Very few entities should be added here, only when absolutely necessary. */ private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; /** * Normal priority queue for normal application operations. * Almost all update events should pass through this queue */ private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; protected static function selectTargetList(string $entityType, bool $withPriority = false): string /** { * Nonblocking low priority queue. This queue will be consumed only when there is nothing * with higher priority. * * This queue will be used for operations such as es:reset-async */ private const string ENTITIES_LOW_PRIORITIES_LIST = '%s-for-update-low'; protected static function selectTargetList( string $entityType, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { if (! in_array($entityType, UpdateTarget::allowedTargets())) { if (! in_array($entityType, UpdateTarget::allowedTargets())) { throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); } } if ($withPriority) { if ($priority->isHigh()) { Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); } } if ($priority->isLow()) { return sprintf(self::ENTITIES_LOW_PRIORITIES_LIST, $entityType); } return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); } } } } app/Component/ES/Processor/TargetEntitiesSelector.php +26-21Lines changed: 26 additions & 21 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SelectionList; use Jiminny\Component\ES\Processor\DTOs\SelectionList; use Jiminny\Component\ES\Processor\Traits\ExtractIdsTrait; use Jiminny\Component\ES\Processor\Traits\ExtractIdsTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\QueuePriorityEnum; /** /** * This class supplies a list of entities pending an update. * This class supplies a list of entities pending an update. public function select(): SelectionList public function select(): SelectionList { { $staleWorkEntityIds = $this->getStaleChunk(); $selectionList = new SelectionList(); $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $staleWorkEntityIds = $this->getStaleChunk(); if (count($staleWorkEntityIds) > 0) { if (count($staleWorkEntityIds) > 0) { return new SelectionList( /** priorityEntityIdList: $staleWorkEntityIds, * Stale chunks are treated as high priority isStaleChunkSelected: true, */ chunkSize: ChunkSize::getStaleChunkSize($this->updateTarget), $selectionList->markStale(); ); $selectionList->addEntityList(QueuePriorityEnum::HIGH, $staleWorkEntityIds); $selectionList->setChunkSize(ChunkSize::getStaleChunkSize($this->updateTarget)); return $selectionList; } } $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $selectionList->setChunkSize($mainChunkSize); $priorityEntityIdsList = $this->extractIdsFromSet( $priorityEntityIdsList = $this->extractIds(QueuePriorityEnum::HIGH, $mainChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, true), $selectionList->addEntityList(QueuePriorityEnum::HIGH, $priorityEntityIdsList); $mainChunkSize, ); $normalEntityIdsList = []; $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); if ($normalEntityChunkSize > 0) { if ($normalEntityChunkSize > 0) { $normalEntityIdsList = $this->extractIdsFromSet( $normalEntityIdsList = $this->extractIds(QueuePriorityEnum::NORMAL, $normalEntityChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, false), $selectionList->addEntityList(QueuePriorityEnum::NORMAL, $normalEntityIdsList); $normalEntityChunkSize ); } } return new SelectionList( return $selectionList; priorityEntityIdList: $priorityEntityIdsList, normalEntityIdList: $normalEntityIdsList, chunkSize: $mainChunkSize ); } } private function getStaleChunk(): array private function getStaleChunk(): array return []; return []; } } private function extractIds(QueuePriorityEnum $priority, int $chunkSize): array { return $this->extractIdsFromSet( AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, $priority), $chunkSize ); } } } app/Component/ES/AsyncUpdateElasticSearch.php +17-10Lines changed: 17 additions & 10 deletions Original file line numberOriginal file lineDiff line numberDiff line change * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * and other activity related data * and other activity related data */ */ public static function markEntityForUpdate(string $entityType, int $entityId, bool $withPriority = false): void public static function markEntityForUpdate( { string $entityType, $targetList = self::selectTargetList($entityType, $withPriority); int $entityId, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { $targetList = self::selectTargetList($entityType, $priority); Redis::sadd($targetList, $entityId); Redis::sadd($targetList, $entityId); Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ 'entityType' => $entityType, 'entityType' => $entityType, 'entityId' => $entityId, 'entityId' => $entityId, 'collectionKey' => $targetList, 'collectionKey' => $targetList, 'withPriority' => $withPriority, 'priority' => $priority->value, ]); ]); } } public static function bulkMarkEntitiesForUpdate( public static function bulkMarkEntitiesForUpdate( string $entityType, string $entityType, array $entityIds, array $entityIds, bool $withPriority = false QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { ): void { if (empty($entityIds)) { if (empty($entityIds)) { return; return; } } $targetList = self::selectTargetList($entityType, $withPriority); $targetList = self::selectTargetList($entityType, $priority); Redis::saddarray($targetList, $entityIds); Redis::saddarray($targetList, $entityIds); } } * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Takes priority into consideration. * Takes priority into consideration. */ */ public static function getEntitiesSourceList(string $updateTarget, $priority = false): string public static function getEntitiesSourceList( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { return self::selectTargetList($updateTarget, $priority); return self::selectTargetList($updateTarget, $priority); } } /** /** * Externally called helper methods * Externally called helper methods * - count and flush * - count and flush */ */ public static function getEntitiesListCount(string $updateTarget, $priority = false): int public static function getEntitiesListCount( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): int { $targetList = self::selectTargetList($updateTarget, $priority); $targetList = self::selectTargetList($updateTarget, $priority); return Redis::scard($targetList); return Redis::scard($targetList); app/Component/ES/QueuePriorityEnum.php +40Lines changed: 40 additions & 0 deletions Original file line numberOriginal file lineDiff line numberDiff line change <?php declare(strict_types=1); namespace Jiminny\Component\ES; use Jiminny\Exceptions\InvalidArgumentException; enum QueuePriorityEnum: string { case HIGH = 'high'; case NORMAL = 'normal'; case LOW = 'low'; public static function tryFromString(string $value): self { if (! self::isValid($value)) { throw new InvalidArgumentException( sprintf('Invalid queue priority "%s" selected', $value) ); } return self::tryFrom($value); } public static function isValid(string $value): bool { return self::tryFrom($value) !== null; } public function isLow(): bool { return $this === self::LOW; } public function isHigh(): bool { return $this === self::HIGH; } } app/Component/ES/UpdateProcessManager.php +12-9Lines changed: 12 additions & 9 deletions Original file line numberOriginal file lineDiff line numberDiff line change if ($selectionList->isEmpty()) { if ($selectionList->isEmpty()) { return false; return false; } } /** /** * A stale chunk will always be smaller than a regular chunk. * A stale chunk will always be smaller than a regular chunk. * That doesn't mean there aren't any other scheduled entities for processing * That doesn't mean there aren't any other scheduled entities for processing private function rescheduleThrottledEntities(SelectionList $selectionList): void private function rescheduleThrottledEntities(SelectionList $selectionList): void { { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $groups = $selectionList->getEntityListGroups(); $this->updateTarget, foreach ($groups as $eachGroup) { $selectionList->getNormalPriorityEntityId() $groupEntityIds = $selectionList->getEntityListItemsByGroup($eachGroup); ); if (! empty($groupEntityIds)) { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $this->updateTarget, entityType: $this->updateTarget, $selectionList->getHighPriorityEntityIds(), entityIds: $groupEntityIds, true priority: QueuePriorityEnum::tryFromString($eachGroup) ); ); } } } } } } app/Console/Commands/Elasticsearch/AsyncUpdateEsEntities.php +9-3Lines changed: 9 additions & 3 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Illuminate\Support\Str; use Illuminate\Support\Str; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Component\ES\UpdateProcessManager; use Jiminny\Component\ES\UpdateProcessManager; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Traits\GracefullyStoppable; use Jiminny\Traits\GracefullyStoppable; Redis::set($gaugeLockName, true); Redis::set($gaugeLockName, true); Redis::expire($gaugeLockName, 60); Redis::expire($gaugeLockName, 60); $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::HIGH), ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update', $updateTarget), stat: sprintf('jiminny.%s-for-update', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::NORMAL), ); ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), stat: sprintf('jiminny.%s-for-update-low', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, true), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::LOW), ); ); } } app/Console/Commands/Elasticsearch/ResetAsyncElasticSearchCommand.php +5-1Lines changed: 5 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\Traits\ValidateUpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\ValidateUpdateTargetTrait; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Component\ES\Repositories\EsResetRepositoryInterface; use Jiminny\Component\ES\Repositories\EsResetRepositoryInterface; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Traits\GracefullyStoppable; use Jiminny\Traits\GracefullyStoppable; private function getRemainingScheduledEntities(bool $printStatus = false): int private function getRemainingScheduledEntities(bool $printStatus = false): int { { $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget, true); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount( $this->updateTarget, QueuePriorityEnum::HIGH ); if ($printStatus) { if ($printStatus) { $this->line( $this->line(
You said
app/Component/ES/Listeners/UpdateMultipleTargetsListener.php
+2-1Lines changed: 2 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\Component\ES\Listeners;
namespace Jiminny\Component\ES\Listeners;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\QueuePriorityEnum;
use Jiminny\Contracts\ES\Events\UpdateMultipleEntities;
use Jiminny\Contracts\ES\Events\UpdateMultipleEntities;
use Psr\Log\LoggerInterface;
use Psr\Log\LoggerInterface;
AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(
AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(
$event->getUpdateTargetValue(),
$event->getUpdateTargetValue(),
$event->getEntities(),
$event->getEntities(),
$event->isPriority()
$event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL,
);
);
}
}
}
}
app/Component/ES/Listeners/UpdateSingleTargetListener.php
+9-1Lines changed: 9 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Actions\TrackElasticSearchOperations;
use Jiminny\Component\ES\Actions\TrackElasticSearchOperations;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\Processor\EntityQueryBuilder;
use Jiminny\Component\ES\Processor\EntityQueryBuilder;
use Jiminny\Component\ES\QueuePriorityEnum;
use Jiminny\Contracts\ES\Events\UpdateSingleEntity;
use Jiminny\Contracts\ES\Events\UpdateSingleEntity;
use Psr\Log\LoggerInterface;
use Psr\Log\LoggerInterface;
'entityId' => $event->getEntityId(),
'entityId' => $event->getEntityId(),
]);
]);
/**
* @important:
* Synchronous event should eventually be deprecated.
* Instant write operations are blocking and should be used sparingly.
* It is much better in terms of performance to write 100 or 1000 documents at once,
* and have one blocking reindex operation, instead of writing 10 documents synchronously.
*/
if ($event->isSyncEvent()) {
if ($event->isSyncEvent()) {
$this->handleSyncEvent($event);
$this->handleSyncEvent($event);
AsyncUpdateElasticSearch::markEntityForUpdate(
AsyncUpdateElasticSearch::markEntityForUpdate(
$event->getUpdateTargetValue(),
$event->getUpdateTargetValue(),
$event->getEntityId(),
$event->getEntityId(),
$event->isPriority()
$event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL,
);
);
}
}
app/Component/ES/Processor/Actions/UpsertDocumentsAction.php
+2-1Lines changed: 2 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SimpleCollection;
use Jiminny\Component\ES\Processor\DTOs\SimpleCollection;
use Jiminny\Component\ES\Processor\ResponseEvaluator;
use Jiminny\Component\ES\Processor\ResponseEvaluator;
use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait;
use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait;
use Jiminny\Component\ES\QueuePriorityEnum;
use Jiminny\Exceptions\InvalidDataException;
use Jiminny\Exceptions\InvalidDataException;
use Sentry\Laravel\Facade as Sentry;
use Sentry\Laravel\Facade as Sentry;
AsyncUpdateElasticSearch::markEntityForUpdate(
AsyncUpdateElasticSearch::markEntityForUpdate(
entityType: $this->updateTarget,
entityType: $this->updateTarget,
entityId: (int) $document->getId(),
entityId: (int) $document->getId(),
withPriority: true
priority: QueuePriorityEnum::HIGH,
);
);
}
}
app/Component/ES/Processor/DTOs/SelectionList.php
+54-17Lines changed: 54 additions & 17 deletions
Original file line numberOriginal file lineDiff line numberDiff line change
namespace Jiminny\Component\ES\Processor\DTOs;
namespace Jiminny\Component\ES\Processor\DTOs;
use Jiminny\Component\ES\QueuePriorityEnum;
/**
/**
* A very basic and simple collection of entity IDs.
* A very basic and simple collection of entity IDs.
*/...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New Tab","depth":4,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Close Google Gemini (⌃X)","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Tabs from other devices","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"AI Chat settings","depth":7,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Close","depth":7,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"WORK, Google Account: lukas.kovalik@jiminny.com","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Main menu","depth":12,"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New chat","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Gemini","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"New Chat","depth":12,"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Open menu for conversation actions.","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXHeading","text":"Conversation with Gemini","depth":15,"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Conversation with Gemini","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Show the uploaded image in a lightbox","depth":21,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy prompt","depth":21,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"You said Make a PR of changes Find potential issues and bottlenecks","depth":21,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"You said","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Make a PR of changes Find potential issues and bottlenecks","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Listen","depth":22,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Show thinking","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Gemini said","depth":20,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Gemini said","depth":21,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"I can see you've uploaded a screenshot of a code diff, likely from a version control system given the red and green highlights. I would love to help you review the changes, spot bottlenecks, and help you draft a Pull Request.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"However,","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"the image resolution is far too low for me to read.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"It appears to be a completely zoomed-out view where the code has been reduced to tiny, illegible pixels. Because of this, I cannot extract any text or logic to analyze.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"How You Can Share the Code","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"How You Can Share the Code","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"To help me review your code effectively, please try one of the following:","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Paste the text directly:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Copy the specific code blocks (both the old and new versions if possible) and paste them directly into our chat.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Upload the files:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"If the changes are extensive, you can upload the raw text or code files.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Take high-resolution screenshots:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"If you must use images, take closer, readable screenshots of the specific functions or methods you want me to review.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Once you provide the readable code, I can dive right in to identify potential bugs, assess performance bottlenecks, and help you summarize the changes for your PR!","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Good response","depth":22,"on_screen":false,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Bad response","depth":22,"on_screen":false,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Share & export","depth":21,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy","depth":22,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Show more options","depth":21,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy prompt","depth":21,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Edit","depth":21,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"You said app/Component/ES/Listeners/UpdateMultipleTargetsListener.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\\Component\\ES\\Listeners; namespace Jiminny\\Component\\ES\\Listeners; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Contracts\\ES\\Events\\UpdateMultipleEntities; use Jiminny\\Contracts\\ES\\Events\\UpdateMultipleEntities; use Psr\\Log\\LoggerInterface; use Psr\\Log\\LoggerInterface; AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntities(), $event->getEntities(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } } } app/Component/ES/Listeners/UpdateSingleTargetListener.php +9-1Lines changed: 9 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Actions\\TrackElasticSearchOperations; use Jiminny\\Component\\ES\\Actions\\TrackElasticSearchOperations; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder; use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Contracts\\ES\\Events\\UpdateSingleEntity; use Jiminny\\Contracts\\ES\\Events\\UpdateSingleEntity; use Psr\\Log\\LoggerInterface; use Psr\\Log\\LoggerInterface; 'entityId' => $event->getEntityId(), 'entityId' => $event->getEntityId(), ]); ]); /** * @important: * Synchronous event should eventually be deprecated. * Instant write operations are blocking and should be used sparingly. * It is much better in terms of performance to write 100 or 1000 documents at once, * and have one blocking reindex operation, instead of writing 10 documents synchronously. */ if ($event->isSyncEvent()) { if ($event->isSyncEvent()) { $this->handleSyncEvent($event); $this->handleSyncEvent($event); AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntityId(), $event->getEntityId(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } app/Component/ES/Processor/Actions/UpsertDocumentsAction.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Processor\\DTOs\\SimpleCollection; use Jiminny\\Component\\ES\\Processor\\DTOs\\SimpleCollection; use Jiminny\\Component\\ES\\Processor\\ResponseEvaluator; use Jiminny\\Component\\ES\\Processor\\ResponseEvaluator; use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait; use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Exceptions\\InvalidDataException; use Jiminny\\Exceptions\\InvalidDataException; use Sentry\\Laravel\\Facade as Sentry; use Sentry\\Laravel\\Facade as Sentry; AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( entityType: $this->updateTarget, entityType: $this->updateTarget, entityId: (int) $document->getId(), entityId: (int) $document->getId(), withPriority: true priority: QueuePriorityEnum::HIGH, ); ); } } app/Component/ES/Processor/DTOs/SelectionList.php +54-17Lines changed: 54 additions & 17 deletions Original file line numberOriginal file lineDiff line numberDiff line change namespace Jiminny\\Component\\ES\\Processor\\DTOs; namespace Jiminny\\Component\\ES\\Processor\\DTOs; use Jiminny\\Component\\ES\\QueuePriorityEnum; /** /** * A very basic and simple collection of entity IDs. * A very basic and simple collection of entity IDs. */ */ class SelectionList class SelectionList { { public function __construct( private const int DEFAULT_CHUNK = 200; private readonly array $priorityEntityIdList = [], private readonly array $normalEntityIdList = [], private int $chunkSize = self::DEFAULT_CHUNK; private readonly bool $isStaleChunkSelected = false, private bool $isStaleChunkSelected = false; private readonly int $chunkSize = 200, private array $selectedEntityIds = []; ) { // Do nothing public function setChunkSize(int $chunkSize): void { $this->chunkSize = $chunkSize; } } public function getAllIds(): array public function markStale(): void { { return array_merge($this->priorityEntityIdList, $this->normalEntityIdList); $this->isStaleChunkSelected = true; } } public function count(): int public function addEntityList(string|QueuePriorityEnum $priority, array $entityIds): void { { return count($this->priorityEntityIdList) + count($this->normalEntityIdList); $priorityKey = $this->normalisePriority($priority); if (! array_key_exists($priorityKey, $this->selectedEntityIds)) { $this->selectedEntityIds[$priorityKey] = []; } $this->selectedEntityIds[$priorityKey] = array_merge($this->selectedEntityIds[$priorityKey], $entityIds); } } public function isEmpty(): bool /** * @return string[] */ public function getEntityListGroups(): array { { return empty($this->priorityEntityIdList) && empty($this->normalEntityIdList); return array_keys($this->selectedEntityIds); } } public function getHighPriorityEntityIds(): array public function getEntityListItemsByGroup(string|QueuePriorityEnum $priority): array { { return $this->priorityEntityIdList; $priorityKey = $this->normalisePriority($priority); return $this->selectedEntityIds[$priorityKey] ?? []; } } public function getNormalPriorityEntityId(): array public function getAllIds(): array { { return $this->normalEntityIdList; $allIds = []; foreach ($this->selectedEntityIds as $entityIds) { $allIds = array_merge($allIds, $entityIds); } return $allIds; } public function count(): int { return array_sum( array_map('count', $this->selectedEntityIds) ); } public function isEmpty(): bool { return $this->count() === 0; } } public function isStaleChunkSelected(): bool public function isStaleChunkSelected(): bool { { return $this->count() >= $this->chunkSize; return $this->count() >= $this->chunkSize; } } private function normalisePriority(string|QueuePriorityEnum $priority): string { return $priority instanceof QueuePriorityEnum ? $priority->value : $priority; } } } app/Component/ES/Processor/Traits/SelectEntityListTrait.php +27-4Lines changed: 27 additions & 4 deletions Original file line numberOriginal file lineDiff line numberDiff line change use Illuminate\\Support\\Facades\\Log; use Illuminate\\Support\\Facades\\Log; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Exceptions\\InvalidArgumentException; use Jiminny\\Exceptions\\InvalidArgumentException; /** /** * Build the correct source list name for the type of entity and priority * Build the correct source list name for the type of entity and priority */ */ trait SelectEntityListTrait trait SelectEntityListTrait { { /** * Highest priority queue for data requiring near-instant availability. * Very few entities should be added here, only when absolutely necessary. */ private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; /** * Normal priority queue for normal application operations. * Almost all update events should pass through this queue */ private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; protected static function selectTargetList(string $entityType, bool $withPriority = false): string /** { * Nonblocking low priority queue. This queue will be consumed only when there is nothing * with higher priority. * * This queue will be used for operations such as es:reset-async */ private const string ENTITIES_LOW_PRIORITIES_LIST = '%s-for-update-low'; protected static function selectTargetList( string $entityType, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { if (! in_array($entityType, UpdateTarget::allowedTargets())) { if (! in_array($entityType, UpdateTarget::allowedTargets())) { throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); } } if ($withPriority) { if ($priority->isHigh()) { Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); } } if ($priority->isLow()) { return sprintf(self::ENTITIES_LOW_PRIORITIES_LIST, $entityType); } return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); } } } } app/Component/ES/Processor/TargetEntitiesSelector.php +26-21Lines changed: 26 additions & 21 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Processor\\DTOs\\SelectionList; use Jiminny\\Component\\ES\\Processor\\DTOs\\SelectionList; use Jiminny\\Component\\ES\\Processor\\Traits\\ExtractIdsTrait; use Jiminny\\Component\\ES\\Processor\\Traits\\ExtractIdsTrait; use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait; use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait; use Jiminny\\Component\\ES\\QueuePriorityEnum; /** /** * This class supplies a list of entities pending an update. * This class supplies a list of entities pending an update. public function select(): SelectionList public function select(): SelectionList { { $staleWorkEntityIds = $this->getStaleChunk(); $selectionList = new SelectionList(); $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $staleWorkEntityIds = $this->getStaleChunk(); if (count($staleWorkEntityIds) > 0) { if (count($staleWorkEntityIds) > 0) { return new SelectionList( /** priorityEntityIdList: $staleWorkEntityIds, * Stale chunks are treated as high priority isStaleChunkSelected: true, */ chunkSize: ChunkSize::getStaleChunkSize($this->updateTarget), $selectionList->markStale(); ); $selectionList->addEntityList(QueuePriorityEnum::HIGH, $staleWorkEntityIds); $selectionList->setChunkSize(ChunkSize::getStaleChunkSize($this->updateTarget)); return $selectionList; } } $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $selectionList->setChunkSize($mainChunkSize); $priorityEntityIdsList = $this->extractIdsFromSet( $priorityEntityIdsList = $this->extractIds(QueuePriorityEnum::HIGH, $mainChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, true), $selectionList->addEntityList(QueuePriorityEnum::HIGH, $priorityEntityIdsList); $mainChunkSize, ); $normalEntityIdsList = []; $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); if ($normalEntityChunkSize > 0) { if ($normalEntityChunkSize > 0) { $normalEntityIdsList = $this->extractIdsFromSet( $normalEntityIdsList = $this->extractIds(QueuePriorityEnum::NORMAL, $normalEntityChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, false), $selectionList->addEntityList(QueuePriorityEnum::NORMAL, $normalEntityIdsList); $normalEntityChunkSize ); } } return new SelectionList( return $selectionList; priorityEntityIdList: $priorityEntityIdsList, normalEntityIdList: $normalEntityIdsList, chunkSize: $mainChunkSize ); } } private function getStaleChunk(): array private function getStaleChunk(): array return []; return []; } } private function extractIds(QueuePriorityEnum $priority, int $chunkSize): array { return $this->extractIdsFromSet( AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, $priority), $chunkSize ); } } } app/Component/ES/AsyncUpdateElasticSearch.php +17-10Lines changed: 17 additions & 10 deletions Original file line numberOriginal file lineDiff line numberDiff line change * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * and other activity related data * and other activity related data */ */ public static function markEntityForUpdate(string $entityType, int $entityId, bool $withPriority = false): void public static function markEntityForUpdate( { string $entityType, $targetList = self::selectTargetList($entityType, $withPriority); int $entityId, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { $targetList = self::selectTargetList($entityType, $priority); Redis::sadd($targetList, $entityId); Redis::sadd($targetList, $entityId); Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ 'entityType' => $entityType, 'entityType' => $entityType, 'entityId' => $entityId, 'entityId' => $entityId, 'collectionKey' => $targetList, 'collectionKey' => $targetList, 'withPriority' => $withPriority, 'priority' => $priority->value, ]); ]); } } public static function bulkMarkEntitiesForUpdate( public static function bulkMarkEntitiesForUpdate( string $entityType, string $entityType, array $entityIds, array $entityIds, bool $withPriority = false QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { ): void { if (empty($entityIds)) { if (empty($entityIds)) { return; return; } } $targetList = self::selectTargetList($entityType, $withPriority); $targetList = self::selectTargetList($entityType, $priority); Redis::saddarray($targetList, $entityIds); Redis::saddarray($targetList, $entityIds); } } * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Takes priority into consideration. * Takes priority into consideration. */ */ public static function getEntitiesSourceList(string $updateTarget, $priority = false): string public static function getEntitiesSourceList( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { return self::selectTargetList($updateTarget, $priority); return self::selectTargetList($updateTarget, $priority); } } /** /** * Externally called helper methods * Externally called helper methods * - count and flush * - count and flush */ */ public static function getEntitiesListCount(string $updateTarget, $priority = false): int public static function getEntitiesListCount( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): int { $targetList = self::selectTargetList($updateTarget, $priority); $targetList = self::selectTargetList($updateTarget, $priority); return Redis::scard($targetList); return Redis::scard($targetList); app/Component/ES/QueuePriorityEnum.php +40Lines changed: 40 additions & 0 deletions Original file line numberOriginal file lineDiff line numberDiff line change <?php declare(strict_types=1); namespace Jiminny\\Component\\ES; use Jiminny\\Exceptions\\InvalidArgumentException; enum QueuePriorityEnum: string { case HIGH = 'high'; case NORMAL = 'normal'; case LOW = 'low'; public static function tryFromString(string $value): self { if (! self::isValid($value)) { throw new InvalidArgumentException( sprintf('Invalid queue priority \"%s\" selected', $value) ); } return self::tryFrom($value); } public static function isValid(string $value): bool { return self::tryFrom($value) !== null; } public function isLow(): bool { return $this === self::LOW; } public function isHigh(): bool { return $this === self::HIGH; } } app/Component/ES/UpdateProcessManager.php +12-9Lines changed: 12 additions & 9 deletions Original file line numberOriginal file lineDiff line numberDiff line change if ($selectionList->isEmpty()) { if ($selectionList->isEmpty()) { return false; return false; } } /** /** * A stale chunk will always be smaller than a regular chunk. * A stale chunk will always be smaller than a regular chunk. * That doesn't mean there aren't any other scheduled entities for processing * That doesn't mean there aren't any other scheduled entities for processing private function rescheduleThrottledEntities(SelectionList $selectionList): void private function rescheduleThrottledEntities(SelectionList $selectionList): void { { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $groups = $selectionList->getEntityListGroups(); $this->updateTarget, foreach ($groups as $eachGroup) { $selectionList->getNormalPriorityEntityId() $groupEntityIds = $selectionList->getEntityListItemsByGroup($eachGroup); ); if (! empty($groupEntityIds)) { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $this->updateTarget, entityType: $this->updateTarget, $selectionList->getHighPriorityEntityIds(), entityIds: $groupEntityIds, true priority: QueuePriorityEnum::tryFromString($eachGroup) ); ); } } } } } } app/Console/Commands/Elasticsearch/AsyncUpdateEsEntities.php +9-3Lines changed: 9 additions & 3 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Illuminate\\Support\\Str; use Illuminate\\Support\\Str; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Component\\ES\\UpdateProcessManager; use Jiminny\\Component\\ES\\UpdateProcessManager; use Jiminny\\Exceptions\\InvalidArgumentException; use Jiminny\\Exceptions\\InvalidArgumentException; use Jiminny\\Traits\\GracefullyStoppable; use Jiminny\\Traits\\GracefullyStoppable; Redis::set($gaugeLockName, true); Redis::set($gaugeLockName, true); Redis::expire($gaugeLockName, 60); Redis::expire($gaugeLockName, 60); $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::HIGH), ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update', $updateTarget), stat: sprintf('jiminny.%s-for-update', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::NORMAL), ); ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), stat: sprintf('jiminny.%s-for-update-low', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, true), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::LOW), ); ); } } app/Console/Commands/Elasticsearch/ResetAsyncElasticSearchCommand.php +5-1Lines changed: 5 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder; use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder; use Jiminny\\Component\\ES\\Processor\\Traits\\ValidateUpdateTargetTrait; use Jiminny\\Component\\ES\\Processor\\Traits\\ValidateUpdateTargetTrait; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Component\\ES\\Repositories\\EsResetRepositoryInterface; use Jiminny\\Component\\ES\\Repositories\\EsResetRepositoryInterface; use Jiminny\\Exceptions\\InvalidArgumentException; use Jiminny\\Exceptions\\InvalidArgumentException; use Jiminny\\Traits\\GracefullyStoppable; use Jiminny\\Traits\\GracefullyStoppable; private function getRemainingScheduledEntities(bool $printStatus = false): int private function getRemainingScheduledEntities(bool $printStatus = false): int { { $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget, true); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount( $this->updateTarget, QueuePriorityEnum::HIGH ); if ($printStatus) { if ($printStatus) { $this->line( $this->line(","depth":21,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"You said","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app/Component/ES/Listeners/UpdateMultipleTargetsListener.php","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"+2-1Lines changed: 2 additions & 1 deletion","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\\Component\\ES\\Listeners;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"namespace Jiminny\\Component\\ES\\Listeners;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\QueuePriorityEnum;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Contracts\\ES\\Events\\UpdateMultipleEntities;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Contracts\\ES\\Events\\UpdateMultipleEntities;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Psr\\Log\\LoggerInterface;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Psr\\Log\\LoggerInterface;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getUpdateTargetValue(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getUpdateTargetValue(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getEntities(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getEntities(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->isPriority()","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL,","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":");","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":");","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app/Component/ES/Listeners/UpdateSingleTargetListener.php","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"+9-1Lines changed: 9 additions & 1 deletion","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Actions\\TrackElasticSearchOperations;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Actions\\TrackElasticSearchOperations;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\QueuePriorityEnum;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Contracts\\ES\\Events\\UpdateSingleEntity;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Contracts\\ES\\Events\\UpdateSingleEntity;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Psr\\Log\\LoggerInterface;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Psr\\Log\\LoggerInterface;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"'entityId' => $event->getEntityId(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"'entityId' => $event->getEntityId(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"]);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"]);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/**","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* @important:","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* Synchronous event should eventually be deprecated.","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* Instant write operations are blocking and should be used sparingly.","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* It is much better in terms of performance to write 100 or 1000 documents at once,","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* and have one blocking reindex operation, instead of writing 10 documents synchronously.","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"*/","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"if ($event->isSyncEvent()) {","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"if ($event->isSyncEvent()) {","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$this->handleSyncEvent($event);","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$this->handleSyncEvent($event);","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AsyncUpdateElasticSearch::markEntityForUpdate(","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AsyncUpdateElasticSearch::markEntityForUpdate(","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getUpdateTargetValue(),","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getUpdateTargetValue(),","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getEntityId(),","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getEntityId(),","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->isPriority()","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL,","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":");","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":");","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app/Component/ES/Processor/Actions/UpsertDocumentsAction.php","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"+2-1Lines changed: 2 additions & 1 deletion","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Processor\\DTOs\\SimpleCollection;","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\DTOs\\SimpleCollection;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\ResponseEvaluator;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\ResponseEvaluator;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\QueuePriorityEnum;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Exceptions\\InvalidDataException;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Exceptions\\InvalidDataException;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Sentry\\Laravel\\Facade as Sentry;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Sentry\\Laravel\\Facade as Sentry;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AsyncUpdateElasticSearch::markEntityForUpdate(","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AsyncUpdateElasticSearch::markEntityForUpdate(","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"entityType: $this->updateTarget,","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"entityType: $this->updateTarget,","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"entityId: (int) $document->getId(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"entityId: (int) $document->getId(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"withPriority: true","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"priority: QueuePriorityEnum::HIGH,","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":");","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":");","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app/Component/ES/Processor/DTOs/SelectionList.php","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"+54-17Lines changed: 54 additions & 17 deletions","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Original file line numberOriginal file lineDiff line numberDiff line change","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"namespace Jiminny\\Component\\ES\\Processor\\DTOs;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"namespace Jiminny\\Component\\ES\\Processor\\DTOs;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\QueuePriorityEnum;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/**","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/**","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* A very basic and simple collection of entity IDs.","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* A very basic and simple collection of entity IDs.","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"*/","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"}]...
|
-2911097373535303289
|
-1127563140626834290
|
click
|
accessibility
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
Close tab
New Tab
Customize sidebar
Close Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
AI Chat settings
Close
WORK, Google Account: [EMAIL]
Main menu
New chat
Gemini
New Chat
Open menu for conversation actions.
Conversation with Gemini
Conversation with Gemini
Show the uploaded image in a lightbox
Copy prompt
You said Make a PR of changes Find potential issues and bottlenecks
You said
Make a PR of changes Find potential issues and bottlenecks
Listen
Show thinking
Gemini said
Gemini said
I can see you've uploaded a screenshot of a code diff, likely from a version control system given the red and green highlights. I would love to help you review the changes, spot bottlenecks, and help you draft a Pull Request.
However,
the image resolution is far too low for me to read.
It appears to be a completely zoomed-out view where the code has been reduced to tiny, illegible pixels. Because of this, I cannot extract any text or logic to analyze.
How You Can Share the Code
How You Can Share the Code
To help me review your code effectively, please try one of the following:
Paste the text directly:
Copy the specific code blocks (both the old and new versions if possible) and paste them directly into our chat.
Upload the files:
If the changes are extensive, you can upload the raw text or code files.
Take high-resolution screenshots:
If you must use images, take closer, readable screenshots of the specific functions or methods you want me to review.
Once you provide the readable code, I can dive right in to identify potential bugs, assess performance bottlenecks, and help you summarize the changes for your PR!
Good response
Bad response
Share & export
Copy
Show more options
Copy prompt
Edit
You said app/Component/ES/Listeners/UpdateMultipleTargetsListener.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\Component\ES\Listeners; namespace Jiminny\Component\ES\Listeners; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Contracts\ES\Events\UpdateMultipleEntities; use Jiminny\Contracts\ES\Events\UpdateMultipleEntities; use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface; AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntities(), $event->getEntities(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } } } app/Component/ES/Listeners/UpdateSingleTargetListener.php +9-1Lines changed: 9 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Actions\TrackElasticSearchOperations; use Jiminny\Component\ES\Actions\TrackElasticSearchOperations; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Contracts\ES\Events\UpdateSingleEntity; use Jiminny\Contracts\ES\Events\UpdateSingleEntity; use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface; 'entityId' => $event->getEntityId(), 'entityId' => $event->getEntityId(), ]); ]); /** * @important: * Synchronous event should eventually be deprecated. * Instant write operations are blocking and should be used sparingly. * It is much better in terms of performance to write 100 or 1000 documents at once, * and have one blocking reindex operation, instead of writing 10 documents synchronously. */ if ($event->isSyncEvent()) { if ($event->isSyncEvent()) { $this->handleSyncEvent($event); $this->handleSyncEvent($event); AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntityId(), $event->getEntityId(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } app/Component/ES/Processor/Actions/UpsertDocumentsAction.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SimpleCollection; use Jiminny\Component\ES\Processor\DTOs\SimpleCollection; use Jiminny\Component\ES\Processor\ResponseEvaluator; use Jiminny\Component\ES\Processor\ResponseEvaluator; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Exceptions\InvalidDataException; use Jiminny\Exceptions\InvalidDataException; use Sentry\Laravel\Facade as Sentry; use Sentry\Laravel\Facade as Sentry; AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( entityType: $this->updateTarget, entityType: $this->updateTarget, entityId: (int) $document->getId(), entityId: (int) $document->getId(), withPriority: true priority: QueuePriorityEnum::HIGH, ); ); } } app/Component/ES/Processor/DTOs/SelectionList.php +54-17Lines changed: 54 additions & 17 deletions Original file line numberOriginal file lineDiff line numberDiff line change namespace Jiminny\Component\ES\Processor\DTOs; namespace Jiminny\Component\ES\Processor\DTOs; use Jiminny\Component\ES\QueuePriorityEnum; /** /** * A very basic and simple collection of entity IDs. * A very basic and simple collection of entity IDs. */ */ class SelectionList class SelectionList { { public function __construct( private const int DEFAULT_CHUNK = 200; private readonly array $priorityEntityIdList = [], private readonly array $normalEntityIdList = [], private int $chunkSize = self::DEFAULT_CHUNK; private readonly bool $isStaleChunkSelected = false, private bool $isStaleChunkSelected = false; private readonly int $chunkSize = 200, private array $selectedEntityIds = []; ) { // Do nothing public function setChunkSize(int $chunkSize): void { $this->chunkSize = $chunkSize; } } public function getAllIds(): array public function markStale(): void { { return array_merge($this->priorityEntityIdList, $this->normalEntityIdList); $this->isStaleChunkSelected = true; } } public function count(): int public function addEntityList(string|QueuePriorityEnum $priority, array $entityIds): void { { return count($this->priorityEntityIdList) + count($this->normalEntityIdList); $priorityKey = $this->normalisePriority($priority); if (! array_key_exists($priorityKey, $this->selectedEntityIds)) { $this->selectedEntityIds[$priorityKey] = []; } $this->selectedEntityIds[$priorityKey] = array_merge($this->selectedEntityIds[$priorityKey], $entityIds); } } public function isEmpty(): bool /** * @return string[] */ public function getEntityListGroups(): array { { return empty($this->priorityEntityIdList) && empty($this->normalEntityIdList); return array_keys($this->selectedEntityIds); } } public function getHighPriorityEntityIds(): array public function getEntityListItemsByGroup(string|QueuePriorityEnum $priority): array { { return $this->priorityEntityIdList; $priorityKey = $this->normalisePriority($priority); return $this->selectedEntityIds[$priorityKey] ?? []; } } public function getNormalPriorityEntityId(): array public function getAllIds(): array { { return $this->normalEntityIdList; $allIds = []; foreach ($this->selectedEntityIds as $entityIds) { $allIds = array_merge($allIds, $entityIds); } return $allIds; } public function count(): int { return array_sum( array_map('count', $this->selectedEntityIds) ); } public function isEmpty(): bool { return $this->count() === 0; } } public function isStaleChunkSelected(): bool public function isStaleChunkSelected(): bool { { return $this->count() >= $this->chunkSize; return $this->count() >= $this->chunkSize; } } private function normalisePriority(string|QueuePriorityEnum $priority): string { return $priority instanceof QueuePriorityEnum ? $priority->value : $priority; } } } app/Component/ES/Processor/Traits/SelectEntityListTrait.php +27-4Lines changed: 27 additions & 4 deletions Original file line numberOriginal file lineDiff line numberDiff line change use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; /** /** * Build the correct source list name for the type of entity and priority * Build the correct source list name for the type of entity and priority */ */ trait SelectEntityListTrait trait SelectEntityListTrait { { /** * Highest priority queue for data requiring near-instant availability. * Very few entities should be added here, only when absolutely necessary. */ private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; /** * Normal priority queue for normal application operations. * Almost all update events should pass through this queue */ private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; protected static function selectTargetList(string $entityType, bool $withPriority = false): string /** { * Nonblocking low priority queue. This queue will be consumed only when there is nothing * with higher priority. * * This queue will be used for operations such as es:reset-async */ private const string ENTITIES_LOW_PRIORITIES_LIST = '%s-for-update-low'; protected static function selectTargetList( string $entityType, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { if (! in_array($entityType, UpdateTarget::allowedTargets())) { if (! in_array($entityType, UpdateTarget::allowedTargets())) { throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); } } if ($withPriority) { if ($priority->isHigh()) { Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); } } if ($priority->isLow()) { return sprintf(self::ENTITIES_LOW_PRIORITIES_LIST, $entityType); } return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); } } } } app/Component/ES/Processor/TargetEntitiesSelector.php +26-21Lines changed: 26 additions & 21 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SelectionList; use Jiminny\Component\ES\Processor\DTOs\SelectionList; use Jiminny\Component\ES\Processor\Traits\ExtractIdsTrait; use Jiminny\Component\ES\Processor\Traits\ExtractIdsTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\QueuePriorityEnum; /** /** * This class supplies a list of entities pending an update. * This class supplies a list of entities pending an update. public function select(): SelectionList public function select(): SelectionList { { $staleWorkEntityIds = $this->getStaleChunk(); $selectionList = new SelectionList(); $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $staleWorkEntityIds = $this->getStaleChunk(); if (count($staleWorkEntityIds) > 0) { if (count($staleWorkEntityIds) > 0) { return new SelectionList( /** priorityEntityIdList: $staleWorkEntityIds, * Stale chunks are treated as high priority isStaleChunkSelected: true, */ chunkSize: ChunkSize::getStaleChunkSize($this->updateTarget), $selectionList->markStale(); ); $selectionList->addEntityList(QueuePriorityEnum::HIGH, $staleWorkEntityIds); $selectionList->setChunkSize(ChunkSize::getStaleChunkSize($this->updateTarget)); return $selectionList; } } $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $selectionList->setChunkSize($mainChunkSize); $priorityEntityIdsList = $this->extractIdsFromSet( $priorityEntityIdsList = $this->extractIds(QueuePriorityEnum::HIGH, $mainChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, true), $selectionList->addEntityList(QueuePriorityEnum::HIGH, $priorityEntityIdsList); $mainChunkSize, ); $normalEntityIdsList = []; $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); if ($normalEntityChunkSize > 0) { if ($normalEntityChunkSize > 0) { $normalEntityIdsList = $this->extractIdsFromSet( $normalEntityIdsList = $this->extractIds(QueuePriorityEnum::NORMAL, $normalEntityChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, false), $selectionList->addEntityList(QueuePriorityEnum::NORMAL, $normalEntityIdsList); $normalEntityChunkSize ); } } return new SelectionList( return $selectionList; priorityEntityIdList: $priorityEntityIdsList, normalEntityIdList: $normalEntityIdsList, chunkSize: $mainChunkSize ); } } private function getStaleChunk(): array private function getStaleChunk(): array return []; return []; } } private function extractIds(QueuePriorityEnum $priority, int $chunkSize): array { return $this->extractIdsFromSet( AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, $priority), $chunkSize ); } } } app/Component/ES/AsyncUpdateElasticSearch.php +17-10Lines changed: 17 additions & 10 deletions Original file line numberOriginal file lineDiff line numberDiff line change * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * and other activity related data * and other activity related data */ */ public static function markEntityForUpdate(string $entityType, int $entityId, bool $withPriority = false): void public static function markEntityForUpdate( { string $entityType, $targetList = self::selectTargetList($entityType, $withPriority); int $entityId, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { $targetList = self::selectTargetList($entityType, $priority); Redis::sadd($targetList, $entityId); Redis::sadd($targetList, $entityId); Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ 'entityType' => $entityType, 'entityType' => $entityType, 'entityId' => $entityId, 'entityId' => $entityId, 'collectionKey' => $targetList, 'collectionKey' => $targetList, 'withPriority' => $withPriority, 'priority' => $priority->value, ]); ]); } } public static function bulkMarkEntitiesForUpdate( public static function bulkMarkEntitiesForUpdate( string $entityType, string $entityType, array $entityIds, array $entityIds, bool $withPriority = false QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { ): void { if (empty($entityIds)) { if (empty($entityIds)) { return; return; } } $targetList = self::selectTargetList($entityType, $withPriority); $targetList = self::selectTargetList($entityType, $priority); Redis::saddarray($targetList, $entityIds); Redis::saddarray($targetList, $entityIds); } } * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Takes priority into consideration. * Takes priority into consideration. */ */ public static function getEntitiesSourceList(string $updateTarget, $priority = false): string public static function getEntitiesSourceList( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { return self::selectTargetList($updateTarget, $priority); return self::selectTargetList($updateTarget, $priority); } } /** /** * Externally called helper methods * Externally called helper methods * - count and flush * - count and flush */ */ public static function getEntitiesListCount(string $updateTarget, $priority = false): int public static function getEntitiesListCount( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): int { $targetList = self::selectTargetList($updateTarget, $priority); $targetList = self::selectTargetList($updateTarget, $priority); return Redis::scard($targetList); return Redis::scard($targetList); app/Component/ES/QueuePriorityEnum.php +40Lines changed: 40 additions & 0 deletions Original file line numberOriginal file lineDiff line numberDiff line change <?php declare(strict_types=1); namespace Jiminny\Component\ES; use Jiminny\Exceptions\InvalidArgumentException; enum QueuePriorityEnum: string { case HIGH = 'high'; case NORMAL = 'normal'; case LOW = 'low'; public static function tryFromString(string $value): self { if (! self::isValid($value)) { throw new InvalidArgumentException( sprintf('Invalid queue priority "%s" selected', $value) ); } return self::tryFrom($value); } public static function isValid(string $value): bool { return self::tryFrom($value) !== null; } public function isLow(): bool { return $this === self::LOW; } public function isHigh(): bool { return $this === self::HIGH; } } app/Component/ES/UpdateProcessManager.php +12-9Lines changed: 12 additions & 9 deletions Original file line numberOriginal file lineDiff line numberDiff line change if ($selectionList->isEmpty()) { if ($selectionList->isEmpty()) { return false; return false; } } /** /** * A stale chunk will always be smaller than a regular chunk. * A stale chunk will always be smaller than a regular chunk. * That doesn't mean there aren't any other scheduled entities for processing * That doesn't mean there aren't any other scheduled entities for processing private function rescheduleThrottledEntities(SelectionList $selectionList): void private function rescheduleThrottledEntities(SelectionList $selectionList): void { { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $groups = $selectionList->getEntityListGroups(); $this->updateTarget, foreach ($groups as $eachGroup) { $selectionList->getNormalPriorityEntityId() $groupEntityIds = $selectionList->getEntityListItemsByGroup($eachGroup); ); if (! empty($groupEntityIds)) { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $this->updateTarget, entityType: $this->updateTarget, $selectionList->getHighPriorityEntityIds(), entityIds: $groupEntityIds, true priority: QueuePriorityEnum::tryFromString($eachGroup) ); ); } } } } } } app/Console/Commands/Elasticsearch/AsyncUpdateEsEntities.php +9-3Lines changed: 9 additions & 3 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Illuminate\Support\Str; use Illuminate\Support\Str; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Component\ES\UpdateProcessManager; use Jiminny\Component\ES\UpdateProcessManager; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Traits\GracefullyStoppable; use Jiminny\Traits\GracefullyStoppable; Redis::set($gaugeLockName, true); Redis::set($gaugeLockName, true); Redis::expire($gaugeLockName, 60); Redis::expire($gaugeLockName, 60); $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::HIGH), ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update', $updateTarget), stat: sprintf('jiminny.%s-for-update', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::NORMAL), ); ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), stat: sprintf('jiminny.%s-for-update-low', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, true), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::LOW), ); ); } } app/Console/Commands/Elasticsearch/ResetAsyncElasticSearchCommand.php +5-1Lines changed: 5 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\Traits\ValidateUpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\ValidateUpdateTargetTrait; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Component\ES\Repositories\EsResetRepositoryInterface; use Jiminny\Component\ES\Repositories\EsResetRepositoryInterface; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Traits\GracefullyStoppable; use Jiminny\Traits\GracefullyStoppable; private function getRemainingScheduledEntities(bool $printStatus = false): int private function getRemainingScheduledEntities(bool $printStatus = false): int { { $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget, true); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount( $this->updateTarget, QueuePriorityEnum::HIGH ); if ($printStatus) { if ($printStatus) { $this->line( $this->line(
You said
app/Component/ES/Listeners/UpdateMultipleTargetsListener.php
+2-1Lines changed: 2 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\Component\ES\Listeners;
namespace Jiminny\Component\ES\Listeners;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\QueuePriorityEnum;
use Jiminny\Contracts\ES\Events\UpdateMultipleEntities;
use Jiminny\Contracts\ES\Events\UpdateMultipleEntities;
use Psr\Log\LoggerInterface;
use Psr\Log\LoggerInterface;
AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(
AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(
$event->getUpdateTargetValue(),
$event->getUpdateTargetValue(),
$event->getEntities(),
$event->getEntities(),
$event->isPriority()
$event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL,
);
);
}
}
}
}
app/Component/ES/Listeners/UpdateSingleTargetListener.php
+9-1Lines changed: 9 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Actions\TrackElasticSearchOperations;
use Jiminny\Component\ES\Actions\TrackElasticSearchOperations;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\Processor\EntityQueryBuilder;
use Jiminny\Component\ES\Processor\EntityQueryBuilder;
use Jiminny\Component\ES\QueuePriorityEnum;
use Jiminny\Contracts\ES\Events\UpdateSingleEntity;
use Jiminny\Contracts\ES\Events\UpdateSingleEntity;
use Psr\Log\LoggerInterface;
use Psr\Log\LoggerInterface;
'entityId' => $event->getEntityId(),
'entityId' => $event->getEntityId(),
]);
]);
/**
* @important:
* Synchronous event should eventually be deprecated.
* Instant write operations are blocking and should be used sparingly.
* It is much better in terms of performance to write 100 or 1000 documents at once,
* and have one blocking reindex operation, instead of writing 10 documents synchronously.
*/
if ($event->isSyncEvent()) {
if ($event->isSyncEvent()) {
$this->handleSyncEvent($event);
$this->handleSyncEvent($event);
AsyncUpdateElasticSearch::markEntityForUpdate(
AsyncUpdateElasticSearch::markEntityForUpdate(
$event->getUpdateTargetValue(),
$event->getUpdateTargetValue(),
$event->getEntityId(),
$event->getEntityId(),
$event->isPriority()
$event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL,
);
);
}
}
app/Component/ES/Processor/Actions/UpsertDocumentsAction.php
+2-1Lines changed: 2 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SimpleCollection;
use Jiminny\Component\ES\Processor\DTOs\SimpleCollection;
use Jiminny\Component\ES\Processor\ResponseEvaluator;
use Jiminny\Component\ES\Processor\ResponseEvaluator;
use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait;
use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait;
use Jiminny\Component\ES\QueuePriorityEnum;
use Jiminny\Exceptions\InvalidDataException;
use Jiminny\Exceptions\InvalidDataException;
use Sentry\Laravel\Facade as Sentry;
use Sentry\Laravel\Facade as Sentry;
AsyncUpdateElasticSearch::markEntityForUpdate(
AsyncUpdateElasticSearch::markEntityForUpdate(
entityType: $this->updateTarget,
entityType: $this->updateTarget,
entityId: (int) $document->getId(),
entityId: (int) $document->getId(),
withPriority: true
priority: QueuePriorityEnum::HIGH,
);
);
}
}
app/Component/ES/Processor/DTOs/SelectionList.php
+54-17Lines changed: 54 additions & 17 deletions
Original file line numberOriginal file lineDiff line numberDiff line change
namespace Jiminny\Component\ES\Processor\DTOs;
namespace Jiminny\Component\ES\Processor\DTOs;
use Jiminny\Component\ES\QueuePriorityEnum;
/**
/**
* A very basic and simple collection of entity IDs.
* A very basic and simple collection of entity IDs.
*/...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
55700
|
1935
|
2
|
2026-05-19T06:42:52.650953+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779172972650_m2.jpg...
|
Firefox
|
JY-20808 low priority indexing queue by Vasil-Jimi JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app — Work...
|
1
|
github.com/jiminny/app/pull/12082/changes#diff-49a github.com/jiminny/app/pull/12082/changes#diff-49a79d99c97caf7fc27ecb1dbacab5a29d871822caa0db0c71e94957c28c87af...
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
Close tab
New Tab
Customize sidebar
Close Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
AI Chat settings
Close
WORK, Google Account: [EMAIL]
Main menu
New chat
Gemini
New Chat
Open menu for conversation actions.
Conversation with Gemini
Conversation with Gemini
Show the uploaded image in a lightbox
Copy prompt
You said Make a PR of changes Find potential issues and bottlenecks
You said
Make a PR of changes Find potential issues and bottlenecks
Listen
Show thinking
Gemini said
Gemini said
I can see you've uploaded a screenshot of a code diff, likely from a version control system given the red and green highlights. I would love to help you review the changes, spot bottlenecks, and help you draft a Pull Request.
However,
the image resolution is far too low for me to read.
It appears to be a completely zoomed-out view where the code has been reduced to tiny, illegible pixels. Because of this, I cannot extract any text or logic to analyze.
How You Can Share the Code
How You Can Share the Code
To help me review your code effectively, please try one of the following:
Paste the text directly:
Copy the specific code blocks (both the old and new versions if possible) and paste them directly into our chat.
Upload the files:
If the changes are extensive, you can upload the raw text or code files.
Take high-resolution screenshots:
If you must use images, take closer, readable screenshots of the specific functions or methods you want me to review.
Once you provide the readable code, I can dive right in to identify potential bugs, assess performance bottlenecks, and help you summarize the changes for your PR!
Good response
Bad response
Share & export
Copy
Show more options
Copy prompt
Edit
You said app/Component/ES/Listeners/UpdateMultipleTargetsListener.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\Component\ES\Listeners; namespace Jiminny\Component\ES\Listeners; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Contracts\ES\Events\UpdateMultipleEntities; use Jiminny\Contracts\ES\Events\UpdateMultipleEntities; use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface; AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntities(), $event->getEntities(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } } } app/Component/ES/Listeners/UpdateSingleTargetListener.php +9-1Lines changed: 9 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Actions\TrackElasticSearchOperations; use Jiminny\Component\ES\Actions\TrackElasticSearchOperations; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Contracts\ES\Events\UpdateSingleEntity; use Jiminny\Contracts\ES\Events\UpdateSingleEntity; use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface; 'entityId' => $event->getEntityId(), 'entityId' => $event->getEntityId(), ]); ]); /** * @important: * Synchronous event should eventually be deprecated. * Instant write operations are blocking and should be used sparingly. * It is much better in terms of performance to write 100 or 1000 documents at once, * and have one blocking reindex operation, instead of writing 10 documents synchronously. */ if ($event->isSyncEvent()) { if ($event->isSyncEvent()) { $this->handleSyncEvent($event); $this->handleSyncEvent($event); AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntityId(), $event->getEntityId(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } app/Component/ES/Processor/Actions/UpsertDocumentsAction.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SimpleCollection; use Jiminny\Component\ES\Processor\DTOs\SimpleCollection; use Jiminny\Component\ES\Processor\ResponseEvaluator; use Jiminny\Component\ES\Processor\ResponseEvaluator; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Exceptions\InvalidDataException; use Jiminny\Exceptions\InvalidDataException; use Sentry\Laravel\Facade as Sentry; use Sentry\Laravel\Facade as Sentry; AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( entityType: $this->updateTarget, entityType: $this->updateTarget, entityId: (int) $document->getId(), entityId: (int) $document->getId(), withPriority: true priority: QueuePriorityEnum::HIGH, ); ); } } app/Component/ES/Processor/DTOs/SelectionList.php +54-17Lines changed: 54 additions & 17 deletions Original file line numberOriginal file lineDiff line numberDiff line change namespace Jiminny\Component\ES\Processor\DTOs; namespace Jiminny\Component\ES\Processor\DTOs; use Jiminny\Component\ES\QueuePriorityEnum; /** /** * A very basic and simple collection of entity IDs. * A very basic and simple collection of entity IDs. */ */ class SelectionList class SelectionList { { public function __construct( private const int DEFAULT_CHUNK = 200; private readonly array $priorityEntityIdList = [], private readonly array $normalEntityIdList = [], private int $chunkSize = self::DEFAULT_CHUNK; private readonly bool $isStaleChunkSelected = false, private bool $isStaleChunkSelected = false; private readonly int $chunkSize = 200, private array $selectedEntityIds = []; ) { // Do nothing public function setChunkSize(int $chunkSize): void { $this->chunkSize = $chunkSize; } } public function getAllIds(): array public function markStale(): void { { return array_merge($this->priorityEntityIdList, $this->normalEntityIdList); $this->isStaleChunkSelected = true; } } public function count(): int public function addEntityList(string|QueuePriorityEnum $priority, array $entityIds): void { { return count($this->priorityEntityIdList) + count($this->normalEntityIdList); $priorityKey = $this->normalisePriority($priority); if (! array_key_exists($priorityKey, $this->selectedEntityIds)) { $this->selectedEntityIds[$priorityKey] = []; } $this->selectedEntityIds[$priorityKey] = array_merge($this->selectedEntityIds[$priorityKey], $entityIds); } } public function isEmpty(): bool /** * @return string[] */ public function getEntityListGroups(): array { { return empty($this->priorityEntityIdList) && empty($this->normalEntityIdList); return array_keys($this->selectedEntityIds); } } public function getHighPriorityEntityIds(): array public function getEntityListItemsByGroup(string|QueuePriorityEnum $priority): array { { return $this->priorityEntityIdList; $priorityKey = $this->normalisePriority($priority); return $this->selectedEntityIds[$priorityKey] ?? []; } } public function getNormalPriorityEntityId(): array public function getAllIds(): array { { return $this->normalEntityIdList; $allIds = []; foreach ($this->selectedEntityIds as $entityIds) { $allIds = array_merge($allIds, $entityIds); } return $allIds; } public function count(): int { return array_sum( array_map('count', $this->selectedEntityIds) ); } public function isEmpty(): bool { return $this->count() === 0; } } public function isStaleChunkSelected(): bool public function isStaleChunkSelected(): bool { { return $this->count() >= $this->chunkSize; return $this->count() >= $this->chunkSize; } } private function normalisePriority(string|QueuePriorityEnum $priority): string { return $priority instanceof QueuePriorityEnum ? $priority->value : $priority; } } } app/Component/ES/Processor/Traits/SelectEntityListTrait.php +27-4Lines changed: 27 additions & 4 deletions Original file line numberOriginal file lineDiff line numberDiff line change use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; /** /** * Build the correct source list name for the type of entity and priority * Build the correct source list name for the type of entity and priority */ */ trait SelectEntityListTrait trait SelectEntityListTrait { { /** * Highest priority queue for data requiring near-instant availability. * Very few entities should be added here, only when absolutely necessary. */ private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; /** * Normal priority queue for normal application operations. * Almost all update events should pass through this queue */ private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; protected static function selectTargetList(string $entityType, bool $withPriority = false): string /** { * Nonblocking low priority queue. This queue will be consumed only when there is nothing * with higher priority. * * This queue will be used for operations such as es:reset-async */ private const string ENTITIES_LOW_PRIORITIES_LIST = '%s-for-update-low'; protected static function selectTargetList( string $entityType, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { if (! in_array($entityType, UpdateTarget::allowedTargets())) { if (! in_array($entityType, UpdateTarget::allowedTargets())) { throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); } } if ($withPriority) { if ($priority->isHigh()) { Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); } } if ($priority->isLow()) { return sprintf(self::ENTITIES_LOW_PRIORITIES_LIST, $entityType); } return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); } } } } app/Component/ES/Processor/TargetEntitiesSelector.php +26-21Lines changed: 26 additions & 21 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SelectionList; use Jiminny\Component\ES\Processor\DTOs\SelectionList; use Jiminny\Component\ES\Processor\Traits\ExtractIdsTrait; use Jiminny\Component\ES\Processor\Traits\ExtractIdsTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\QueuePriorityEnum; /** /** * This class supplies a list of entities pending an update. * This class supplies a list of entities pending an update. public function select(): SelectionList public function select(): SelectionList { { $staleWorkEntityIds = $this->getStaleChunk(); $selectionList = new SelectionList(); $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $staleWorkEntityIds = $this->getStaleChunk(); if (count($staleWorkEntityIds) > 0) { if (count($staleWorkEntityIds) > 0) { return new SelectionList( /** priorityEntityIdList: $staleWorkEntityIds, * Stale chunks are treated as high priority isStaleChunkSelected: true, */ chunkSize: ChunkSize::getStaleChunkSize($this->updateTarget), $selectionList->markStale(); ); $selectionList->addEntityList(QueuePriorityEnum::HIGH, $staleWorkEntityIds); $selectionList->setChunkSize(ChunkSize::getStaleChunkSize($this->updateTarget)); return $selectionList; } } $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $selectionList->setChunkSize($mainChunkSize); $priorityEntityIdsList = $this->extractIdsFromSet( $priorityEntityIdsList = $this->extractIds(QueuePriorityEnum::HIGH, $mainChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, true), $selectionList->addEntityList(QueuePriorityEnum::HIGH, $priorityEntityIdsList); $mainChunkSize, ); $normalEntityIdsList = []; $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); if ($normalEntityChunkSize > 0) { if ($normalEntityChunkSize > 0) { $normalEntityIdsList = $this->extractIdsFromSet( $normalEntityIdsList = $this->extractIds(QueuePriorityEnum::NORMAL, $normalEntityChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, false), $selectionList->addEntityList(QueuePriorityEnum::NORMAL, $normalEntityIdsList); $normalEntityChunkSize ); } } return new SelectionList( return $selectionList; priorityEntityIdList: $priorityEntityIdsList, normalEntityIdList: $normalEntityIdsList, chunkSize: $mainChunkSize ); } } private function getStaleChunk(): array private function getStaleChunk(): array return []; return []; } } private function extractIds(QueuePriorityEnum $priority, int $chunkSize): array { return $this->extractIdsFromSet( AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, $priority), $chunkSize ); } } } app/Component/ES/AsyncUpdateElasticSearch.php +17-10Lines changed: 17 additions & 10 deletions Original file line numberOriginal file lineDiff line numberDiff line change * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * and other activity related data * and other activity related data */ */ public static function markEntityForUpdate(string $entityType, int $entityId, bool $withPriority = false): void public static function markEntityForUpdate( { string $entityType, $targetList = self::selectTargetList($entityType, $withPriority); int $entityId, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { $targetList = self::selectTargetList($entityType, $priority); Redis::sadd($targetList, $entityId); Redis::sadd($targetList, $entityId); Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ 'entityType' => $entityType, 'entityType' => $entityType, 'entityId' => $entityId, 'entityId' => $entityId, 'collectionKey' => $targetList, 'collectionKey' => $targetList, 'withPriority' => $withPriority, 'priority' => $priority->value, ]); ]); } } public static function bulkMarkEntitiesForUpdate( public static function bulkMarkEntitiesForUpdate( string $entityType, string $entityType, array $entityIds, array $entityIds, bool $withPriority = false QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { ): void { if (empty($entityIds)) { if (empty($entityIds)) { return; return; } } $targetList = self::selectTargetList($entityType, $withPriority); $targetList = self::selectTargetList($entityType, $priority); Redis::saddarray($targetList, $entityIds); Redis::saddarray($targetList, $entityIds); } } * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Takes priority into consideration. * Takes priority into consideration. */ */ public static function getEntitiesSourceList(string $updateTarget, $priority = false): string public static function getEntitiesSourceList( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { return self::selectTargetList($updateTarget, $priority); return self::selectTargetList($updateTarget, $priority); } } /** /** * Externally called helper methods * Externally called helper methods * - count and flush * - count and flush */ */ public static function getEntitiesListCount(string $updateTarget, $priority = false): int public static function getEntitiesListCount( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): int { $targetList = self::selectTargetList($updateTarget, $priority); $targetList = self::selectTargetList($updateTarget, $priority); return Redis::scard($targetList); return Redis::scard($targetList); app/Component/ES/QueuePriorityEnum.php +40Lines changed: 40 additions & 0 deletions Original file line numberOriginal file lineDiff line numberDiff line change <?php declare(strict_types=1); namespace Jiminny\Component\ES; use Jiminny\Exceptions\InvalidArgumentException; enum QueuePriorityEnum: string { case HIGH = 'high'; case NORMAL = 'normal'; case LOW = 'low'; public static function tryFromString(string $value): self { if (! self::isValid($value)) { throw new InvalidArgumentException( sprintf('Invalid queue priority "%s" selected', $value) ); } return self::tryFrom($value); } public static function isValid(string $value): bool { return self::tryFrom($value) !== null; } public function isLow(): bool { return $this === self::LOW; } public function isHigh(): bool { return $this === self::HIGH; } } app/Component/ES/UpdateProcessManager.php +12-9Lines changed: 12 additions & 9 deletions Original file line numberOriginal file lineDiff line numberDiff line change if ($selectionList->isEmpty()) { if ($selectionList->isEmpty()) { return false; return false; } } /** /** * A stale chunk will always be smaller than a regular chunk. * A stale chunk will always be smaller than a regular chunk. * That doesn't mean there aren't any other scheduled entities for processing * That doesn't mean there aren't any other scheduled entities for processing private function rescheduleThrottledEntities(SelectionList $selectionList): void private function rescheduleThrottledEntities(SelectionList $selectionList): void { { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $groups = $selectionList->getEntityListGroups(); $this->updateTarget, foreach ($groups as $eachGroup) { $selectionList->getNormalPriorityEntityId() $groupEntityIds = $selectionList->getEntityListItemsByGroup($eachGroup); ); if (! empty($groupEntityIds)) { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $this->updateTarget, entityType: $this->updateTarget, $selectionList->getHighPriorityEntityIds(), entityIds: $groupEntityIds, true priority: QueuePriorityEnum::tryFromString($eachGroup) ); ); } } } } } } app/Console/Commands/Elasticsearch/AsyncUpdateEsEntities.php +9-3Lines changed: 9 additions & 3 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Illuminate\Support\Str; use Illuminate\Support\Str; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Component\ES\UpdateProcessManager; use Jiminny\Component\ES\UpdateProcessManager; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Traits\GracefullyStoppable; use Jiminny\Traits\GracefullyStoppable; Redis::set($gaugeLockName, true); Redis::set($gaugeLockName, true); Redis::expire($gaugeLockName, 60); Redis::expire($gaugeLockName, 60); $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::HIGH), ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update', $updateTarget), stat: sprintf('jiminny.%s-for-update', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::NORMAL), ); ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), stat: sprintf('jiminny.%s-for-update-low', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, true), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::LOW), ); ); } } app/Console/Commands/Elasticsearch/ResetAsyncElasticSearchCommand.php +5-1Lines changed: 5 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\Traits\ValidateUpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\ValidateUpdateTargetTrait; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Component\ES\Repositories\EsResetRepositoryInterface; use Jiminny\Component\ES\Repositories\EsResetRepositoryInterface; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Traits\GracefullyStoppable; use Jiminny\Traits\GracefullyStoppable; private function getRemainingScheduledEntities(bool $printStatus = false): int private function getRemainingScheduledEntities(bool $printStatus = false): int { { $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget, true); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount( $this->updateTarget, QueuePriorityEnum::HIGH ); if ($printStatus) { if ($printStatus) { $this->line( $this->line(
You said
app/Component/ES/Listeners/UpdateMultipleTargetsListener.php
+2-1Lines changed: 2 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\Component\ES\Listeners;
namespace Jiminny\Component\ES\Listeners;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\QueuePriorityEnum;
use Jiminny\Contracts\ES\Events\UpdateMultipleEntities;
use Jiminny\Contracts\ES\Events\UpdateMultipleEntities;
use Psr\Log\LoggerInterface;
use Psr\Log\LoggerInterface;
AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(
AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(
$event->getUpdateTargetValue(),
$event->getUpdateTargetValue(),
$event->getEntities(),
$event->getEntities(),
$event->isPriority()
$event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL,
);
);
}
}
}
}
app/Component/ES/Listeners/UpdateSingleTargetListener.php
+9-1Lines changed: 9 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Actions\TrackElasticSearchOperations;
use Jiminny\Component\ES\Actions\TrackElasticSearchOperations;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\Processor\EntityQueryBuilder;
use Jiminny\Component\ES\Processor\EntityQueryBuilder;
use Jiminny\Component\ES\QueuePriorityEnum;
use Jiminny\Contracts\ES\Events\UpdateSingleEntity;
use Jiminny\Contracts\ES\Events\UpdateSingleEntity;
use Psr\Log\LoggerInterface;
use Psr\Log\LoggerInterface;
'entityId' => $event->getEntityId(),
'entityId' => $event->getEntityId(),
]);
]);
/**
* @important:
* Synchronous event should eventually be deprecated.
* Instant write operations are blocking and should be used sparingly.
* It is much better in terms of performance to write 100 or 1000 documents at once,
* and have one blocking reindex operation, instead of writing 10 documents synchronously.
*/
if ($event->isSyncEvent()) {
if ($event->isSyncEvent()) {
$this->handleSyncEvent($event);
$this->handleSyncEvent($event);
AsyncUpdateElasticSearch::markEntityForUpdate(
AsyncUpdateElasticSearch::markEntityForUpdate(
$event->getUpdateTargetValue(),
$event->getUpdateTargetValue(),
$event->getEntityId(),
$event->getEntityId(),
$event->isPriority()
$event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL,
);
);
}
}
app/Component/ES/Processor/Actions/UpsertDocumentsAction.php
+2-1Lines changed: 2 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SimpleCollection;
use Jiminny\Component\ES\Processor\DTOs\SimpleCollection;
use Jiminny\Component\ES\Processor\ResponseEvaluator;
use Jiminny\Component\ES\Processor\ResponseEvaluator;
use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait;
use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait;
use Jiminny\Component\ES\QueuePriorityEnum;
use Jiminny\Exceptions\InvalidDataException;
use Jiminny\Exceptions\InvalidDataException;
use Sentry\Laravel\Facade as Sentry;
use Sentry\Laravel\Facade as Sentry;
AsyncUpdateElasticSearch::markEntityForUpdate(
AsyncUpdateElasticSearch::markEntityForUpdate(
entityType: $this->updateTarget,
entityType: $this->updateTarget,
entityId: (int) $document->getId(),
entityId: (int) $document->getId(),
withPriority: true
priority: QueuePriorityEnum::HIGH,
);
);
}
}
app/Component/ES/Processor/DTOs/SelectionList.php
+54-17Lines changed: 54 additions & 17 deletions
Original file line numberOriginal file lineDiff line numberDiff line change
namespace Jiminny\Component\ES\Processor\DTOs;
namespace Jiminny\Component\ES\Processor\DTOs;
use Jiminny\Component\ES\QueuePriorityEnum;
/**
/**
* A very basic and simple collection of entity IDs.
* A very basic and simple collection of entity IDs.
*/
*/
class SelectionList
class SelectionList
{
{
public function __construct(
private const int DEFAULT_CHUNK = 200;
private readonly array $priorityEntityIdList = [],
private readonly array $normalEntityIdList = [],
private int $chunkSize = self::DEFAULT_CHUNK;
private readonly bool $isStaleChunkSelected = false,
private bool $isStaleChunkSelected = false;
private readonly int $chunkSize = 200,
private array $selectedEntityIds = [];
) {
// Do nothing
public function setChunkSize(int $chunkSize): void
{
$this->chunkSize = $chunkSize;
}
}
public function getAllIds(): array
public function markStale(): void
{
{
return array_merge($this->priorityEntityIdList, $this->normalEntityIdList);
$this->isStaleChunkSelected = true;
}
}
public function count(): int
public function addEntityList(string|QueuePriorityEnum $priority, array $entityIds): void
{
{
return count($this->priorityEntityIdList) + count($this->normalEntityIdList);
$priorityKey = $this->normalisePriority($priority);
if (! array_key_exists($priorityKey, $this->selectedEntityIds)) {
$this->selectedEntityIds[$priorityKey] = [];
}
$this->selectedEntityIds[$priorityKey] = array_merge($this->selectedEntityIds[$priorityKey], $entityIds);
}
}
public function isEmpty(): bool
/**
* @return string[]
*/
public function getEntityListGroups(): array
{
{
return empty($this->priorityEntityIdList) && empty($this->normalEntityIdList);
return array_keys($this->selectedEntityIds);
}
}
public function getHighPriorityEntityIds(): array
public function getEntityListItemsByGroup(string|QueuePriorityEnum $priority): array
{
{
return $this->priorityEntityIdList;
$priorityKey = $this->normalisePriority($priority);
return $this->selectedEntityIds[$priorityKey] ?? [];
}
}
public function getNormalPriorityEntityId(): array
public function getAllIds(): array
{
{
return $this->normalEntityIdList;
$allIds = [];
foreach ($this->selectedEntityIds as $entityIds) {
$allIds = array_merge($allIds, $entityIds);
}
return $allIds;
}
public function count(): int
{
return array_sum(
array_map('count', $this->selectedEntityIds)
);
}
public function isEmpty(): bool
{
return $this->count() === 0;
}
}
public function isStaleChunkSelected(): bool
public function isStaleChunkSelected(): bool
{
{
return $this->count() >= $this->chunkSize;
return $this->count() >= $this->chunkSize;
}
}
private function normalisePriority(string|QueuePriorityEnum $priority): string
{
return $priority instanceof QueuePriorityEnum ? $priority->value : $priority;
}
}
}
app/Component/ES/Processor/Traits/SelectEntityListTrait.php
+27-4Lines changed: 27 additions & 4 deletions
Original file line numberOriginal file lineDiff line numberDiff line change
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Log;
use Jiminny\Component\ES\Processor\UpdateTarget;
use Jiminny\Component\ES\Processor\UpdateTarget;
use Jiminny\Component\ES\QueuePriorityEnum;
use Jiminny\Exceptions\InvalidArgumentException;
use Jiminny\Exceptions\InvalidArgumentException;
/**
/**
* Build the correct source list name for the type of entity and priority
* Build the correct source list name for the type of entity and priority
*/
*/
trait SelectEntityListTrait
trait SelectEntityListTrait
{
{
/**
* Highest priority queue for data requiring near-instant availability....
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira","depth":4,"bounds":{"left":0.0,"top":0.0518755,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.06304868,"width":0.10106383,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app","depth":4,"bounds":{"left":0.0,"top":0.08459697,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app","depth":5,"bounds":{"left":0.013297873,"top":0.09577015,"width":0.18816489,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app","depth":4,"bounds":{"left":0.0,"top":0.11731844,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app","depth":5,"bounds":{"left":0.013297873,"top":0.12849163,"width":0.15674867,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.06732048,"top":0.1245012,"width":0.007978723,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New Tab","depth":4,"bounds":{"left":0.0028257978,"top":0.15163608,"width":0.07413564,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"bounds":{"left":0.0028257978,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Close Google Gemini (⌃X)","depth":6,"bounds":{"left":0.013796543,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Tabs from other devices","depth":6,"bounds":{"left":0.024933511,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"bounds":{"left":0.036070477,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"bounds":{"left":0.04720745,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"AI Chat settings","depth":7,"bounds":{"left":0.35854387,"top":0.055067837,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Close","depth":7,"bounds":{"left":0.37051198,"top":0.055067837,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"WORK, Google Account: lukas.kovalik@jiminny.com","depth":12,"bounds":{"left":0.3678524,"top":0.103751,"width":0.013297873,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Main menu","depth":12,"bounds":{"left":0.08494016,"top":0.103751,"width":0.013297873,"height":0.031923383},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New chat","depth":12,"bounds":{"left":0.09823803,"top":0.10454908,"width":0.028590426,"height":0.030327214},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Gemini","depth":15,"bounds":{"left":0.1008976,"top":0.10973663,"width":0.021941489,"height":0.020351157},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"New Chat","depth":12,"bounds":{"left":0.33992687,"top":0.103751,"width":0.013297873,"height":0.031923383},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Open menu for conversation actions.","depth":12,"bounds":{"left":0.35322472,"top":0.103751,"width":0.013297873,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXHeading","text":"Conversation with Gemini","depth":15,"bounds":{"left":0.079288565,"top":0.14764565,"width":0.0003324468,"height":0.0007980846},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Conversation with Gemini","depth":16,"bounds":{"left":0.079288565,"top":0.15003991,"width":0.1200133,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Show the uploaded image in a lightbox","depth":21,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy prompt","depth":21,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"You said Make a PR of changes Find potential issues and bottlenecks","depth":21,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"You said","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Make a PR of changes Find potential issues and bottlenecks","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Listen","depth":22,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Show thinking","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Gemini said","depth":20,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Gemini said","depth":21,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"I can see you've uploaded a screenshot of a code diff, likely from a version control system given the red and green highlights. I would love to help you review the changes, spot bottlenecks, and help you draft a Pull Request.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"However,","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"the image resolution is far too low for me to read.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"It appears to be a completely zoomed-out view where the code has been reduced to tiny, illegible pixels. Because of this, I cannot extract any text or logic to analyze.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"How You Can Share the Code","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"How You Can Share the Code","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"To help me review your code effectively, please try one of the following:","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Paste the text directly:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Copy the specific code blocks (both the old and new versions if possible) and paste them directly into our chat.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Upload the files:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"If the changes are extensive, you can upload the raw text or code files.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Take high-resolution screenshots:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"If you must use images, take closer, readable screenshots of the specific functions or methods you want me to review.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Once you provide the readable code, I can dive right in to identify potential bugs, assess performance bottlenecks, and help you summarize the changes for your PR!","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Good response","depth":22,"on_screen":false,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Bad response","depth":22,"on_screen":false,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Share & export","depth":21,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy","depth":22,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Show more options","depth":21,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy prompt","depth":21,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Edit","depth":21,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"You said app/Component/ES/Listeners/UpdateMultipleTargetsListener.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\\Component\\ES\\Listeners; namespace Jiminny\\Component\\ES\\Listeners; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Contracts\\ES\\Events\\UpdateMultipleEntities; use Jiminny\\Contracts\\ES\\Events\\UpdateMultipleEntities; use Psr\\Log\\LoggerInterface; use Psr\\Log\\LoggerInterface; AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntities(), $event->getEntities(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } } } app/Component/ES/Listeners/UpdateSingleTargetListener.php +9-1Lines changed: 9 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Actions\\TrackElasticSearchOperations; use Jiminny\\Component\\ES\\Actions\\TrackElasticSearchOperations; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder; use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Contracts\\ES\\Events\\UpdateSingleEntity; use Jiminny\\Contracts\\ES\\Events\\UpdateSingleEntity; use Psr\\Log\\LoggerInterface; use Psr\\Log\\LoggerInterface; 'entityId' => $event->getEntityId(), 'entityId' => $event->getEntityId(), ]); ]); /** * @important: * Synchronous event should eventually be deprecated. * Instant write operations are blocking and should be used sparingly. * It is much better in terms of performance to write 100 or 1000 documents at once, * and have one blocking reindex operation, instead of writing 10 documents synchronously. */ if ($event->isSyncEvent()) { if ($event->isSyncEvent()) { $this->handleSyncEvent($event); $this->handleSyncEvent($event); AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntityId(), $event->getEntityId(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } app/Component/ES/Processor/Actions/UpsertDocumentsAction.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Processor\\DTOs\\SimpleCollection; use Jiminny\\Component\\ES\\Processor\\DTOs\\SimpleCollection; use Jiminny\\Component\\ES\\Processor\\ResponseEvaluator; use Jiminny\\Component\\ES\\Processor\\ResponseEvaluator; use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait; use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Exceptions\\InvalidDataException; use Jiminny\\Exceptions\\InvalidDataException; use Sentry\\Laravel\\Facade as Sentry; use Sentry\\Laravel\\Facade as Sentry; AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( entityType: $this->updateTarget, entityType: $this->updateTarget, entityId: (int) $document->getId(), entityId: (int) $document->getId(), withPriority: true priority: QueuePriorityEnum::HIGH, ); ); } } app/Component/ES/Processor/DTOs/SelectionList.php +54-17Lines changed: 54 additions & 17 deletions Original file line numberOriginal file lineDiff line numberDiff line change namespace Jiminny\\Component\\ES\\Processor\\DTOs; namespace Jiminny\\Component\\ES\\Processor\\DTOs; use Jiminny\\Component\\ES\\QueuePriorityEnum; /** /** * A very basic and simple collection of entity IDs. * A very basic and simple collection of entity IDs. */ */ class SelectionList class SelectionList { { public function __construct( private const int DEFAULT_CHUNK = 200; private readonly array $priorityEntityIdList = [], private readonly array $normalEntityIdList = [], private int $chunkSize = self::DEFAULT_CHUNK; private readonly bool $isStaleChunkSelected = false, private bool $isStaleChunkSelected = false; private readonly int $chunkSize = 200, private array $selectedEntityIds = []; ) { // Do nothing public function setChunkSize(int $chunkSize): void { $this->chunkSize = $chunkSize; } } public function getAllIds(): array public function markStale(): void { { return array_merge($this->priorityEntityIdList, $this->normalEntityIdList); $this->isStaleChunkSelected = true; } } public function count(): int public function addEntityList(string|QueuePriorityEnum $priority, array $entityIds): void { { return count($this->priorityEntityIdList) + count($this->normalEntityIdList); $priorityKey = $this->normalisePriority($priority); if (! array_key_exists($priorityKey, $this->selectedEntityIds)) { $this->selectedEntityIds[$priorityKey] = []; } $this->selectedEntityIds[$priorityKey] = array_merge($this->selectedEntityIds[$priorityKey], $entityIds); } } public function isEmpty(): bool /** * @return string[] */ public function getEntityListGroups(): array { { return empty($this->priorityEntityIdList) && empty($this->normalEntityIdList); return array_keys($this->selectedEntityIds); } } public function getHighPriorityEntityIds(): array public function getEntityListItemsByGroup(string|QueuePriorityEnum $priority): array { { return $this->priorityEntityIdList; $priorityKey = $this->normalisePriority($priority); return $this->selectedEntityIds[$priorityKey] ?? []; } } public function getNormalPriorityEntityId(): array public function getAllIds(): array { { return $this->normalEntityIdList; $allIds = []; foreach ($this->selectedEntityIds as $entityIds) { $allIds = array_merge($allIds, $entityIds); } return $allIds; } public function count(): int { return array_sum( array_map('count', $this->selectedEntityIds) ); } public function isEmpty(): bool { return $this->count() === 0; } } public function isStaleChunkSelected(): bool public function isStaleChunkSelected(): bool { { return $this->count() >= $this->chunkSize; return $this->count() >= $this->chunkSize; } } private function normalisePriority(string|QueuePriorityEnum $priority): string { return $priority instanceof QueuePriorityEnum ? $priority->value : $priority; } } } app/Component/ES/Processor/Traits/SelectEntityListTrait.php +27-4Lines changed: 27 additions & 4 deletions Original file line numberOriginal file lineDiff line numberDiff line change use Illuminate\\Support\\Facades\\Log; use Illuminate\\Support\\Facades\\Log; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Exceptions\\InvalidArgumentException; use Jiminny\\Exceptions\\InvalidArgumentException; /** /** * Build the correct source list name for the type of entity and priority * Build the correct source list name for the type of entity and priority */ */ trait SelectEntityListTrait trait SelectEntityListTrait { { /** * Highest priority queue for data requiring near-instant availability. * Very few entities should be added here, only when absolutely necessary. */ private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; /** * Normal priority queue for normal application operations. * Almost all update events should pass through this queue */ private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; protected static function selectTargetList(string $entityType, bool $withPriority = false): string /** { * Nonblocking low priority queue. This queue will be consumed only when there is nothing * with higher priority. * * This queue will be used for operations such as es:reset-async */ private const string ENTITIES_LOW_PRIORITIES_LIST = '%s-for-update-low'; protected static function selectTargetList( string $entityType, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { if (! in_array($entityType, UpdateTarget::allowedTargets())) { if (! in_array($entityType, UpdateTarget::allowedTargets())) { throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); } } if ($withPriority) { if ($priority->isHigh()) { Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); } } if ($priority->isLow()) { return sprintf(self::ENTITIES_LOW_PRIORITIES_LIST, $entityType); } return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); } } } } app/Component/ES/Processor/TargetEntitiesSelector.php +26-21Lines changed: 26 additions & 21 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Processor\\DTOs\\SelectionList; use Jiminny\\Component\\ES\\Processor\\DTOs\\SelectionList; use Jiminny\\Component\\ES\\Processor\\Traits\\ExtractIdsTrait; use Jiminny\\Component\\ES\\Processor\\Traits\\ExtractIdsTrait; use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait; use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait; use Jiminny\\Component\\ES\\QueuePriorityEnum; /** /** * This class supplies a list of entities pending an update. * This class supplies a list of entities pending an update. public function select(): SelectionList public function select(): SelectionList { { $staleWorkEntityIds = $this->getStaleChunk(); $selectionList = new SelectionList(); $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $staleWorkEntityIds = $this->getStaleChunk(); if (count($staleWorkEntityIds) > 0) { if (count($staleWorkEntityIds) > 0) { return new SelectionList( /** priorityEntityIdList: $staleWorkEntityIds, * Stale chunks are treated as high priority isStaleChunkSelected: true, */ chunkSize: ChunkSize::getStaleChunkSize($this->updateTarget), $selectionList->markStale(); ); $selectionList->addEntityList(QueuePriorityEnum::HIGH, $staleWorkEntityIds); $selectionList->setChunkSize(ChunkSize::getStaleChunkSize($this->updateTarget)); return $selectionList; } } $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $selectionList->setChunkSize($mainChunkSize); $priorityEntityIdsList = $this->extractIdsFromSet( $priorityEntityIdsList = $this->extractIds(QueuePriorityEnum::HIGH, $mainChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, true), $selectionList->addEntityList(QueuePriorityEnum::HIGH, $priorityEntityIdsList); $mainChunkSize, ); $normalEntityIdsList = []; $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); if ($normalEntityChunkSize > 0) { if ($normalEntityChunkSize > 0) { $normalEntityIdsList = $this->extractIdsFromSet( $normalEntityIdsList = $this->extractIds(QueuePriorityEnum::NORMAL, $normalEntityChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, false), $selectionList->addEntityList(QueuePriorityEnum::NORMAL, $normalEntityIdsList); $normalEntityChunkSize ); } } return new SelectionList( return $selectionList; priorityEntityIdList: $priorityEntityIdsList, normalEntityIdList: $normalEntityIdsList, chunkSize: $mainChunkSize ); } } private function getStaleChunk(): array private function getStaleChunk(): array return []; return []; } } private function extractIds(QueuePriorityEnum $priority, int $chunkSize): array { return $this->extractIdsFromSet( AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, $priority), $chunkSize ); } } } app/Component/ES/AsyncUpdateElasticSearch.php +17-10Lines changed: 17 additions & 10 deletions Original file line numberOriginal file lineDiff line numberDiff line change * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * and other activity related data * and other activity related data */ */ public static function markEntityForUpdate(string $entityType, int $entityId, bool $withPriority = false): void public static function markEntityForUpdate( { string $entityType, $targetList = self::selectTargetList($entityType, $withPriority); int $entityId, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { $targetList = self::selectTargetList($entityType, $priority); Redis::sadd($targetList, $entityId); Redis::sadd($targetList, $entityId); Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ 'entityType' => $entityType, 'entityType' => $entityType, 'entityId' => $entityId, 'entityId' => $entityId, 'collectionKey' => $targetList, 'collectionKey' => $targetList, 'withPriority' => $withPriority, 'priority' => $priority->value, ]); ]); } } public static function bulkMarkEntitiesForUpdate( public static function bulkMarkEntitiesForUpdate( string $entityType, string $entityType, array $entityIds, array $entityIds, bool $withPriority = false QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { ): void { if (empty($entityIds)) { if (empty($entityIds)) { return; return; } } $targetList = self::selectTargetList($entityType, $withPriority); $targetList = self::selectTargetList($entityType, $priority); Redis::saddarray($targetList, $entityIds); Redis::saddarray($targetList, $entityIds); } } * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Takes priority into consideration. * Takes priority into consideration. */ */ public static function getEntitiesSourceList(string $updateTarget, $priority = false): string public static function getEntitiesSourceList( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { return self::selectTargetList($updateTarget, $priority); return self::selectTargetList($updateTarget, $priority); } } /** /** * Externally called helper methods * Externally called helper methods * - count and flush * - count and flush */ */ public static function getEntitiesListCount(string $updateTarget, $priority = false): int public static function getEntitiesListCount( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): int { $targetList = self::selectTargetList($updateTarget, $priority); $targetList = self::selectTargetList($updateTarget, $priority); return Redis::scard($targetList); return Redis::scard($targetList); app/Component/ES/QueuePriorityEnum.php +40Lines changed: 40 additions & 0 deletions Original file line numberOriginal file lineDiff line numberDiff line change <?php declare(strict_types=1); namespace Jiminny\\Component\\ES; use Jiminny\\Exceptions\\InvalidArgumentException; enum QueuePriorityEnum: string { case HIGH = 'high'; case NORMAL = 'normal'; case LOW = 'low'; public static function tryFromString(string $value): self { if (! self::isValid($value)) { throw new InvalidArgumentException( sprintf('Invalid queue priority \"%s\" selected', $value) ); } return self::tryFrom($value); } public static function isValid(string $value): bool { return self::tryFrom($value) !== null; } public function isLow(): bool { return $this === self::LOW; } public function isHigh(): bool { return $this === self::HIGH; } } app/Component/ES/UpdateProcessManager.php +12-9Lines changed: 12 additions & 9 deletions Original file line numberOriginal file lineDiff line numberDiff line change if ($selectionList->isEmpty()) { if ($selectionList->isEmpty()) { return false; return false; } } /** /** * A stale chunk will always be smaller than a regular chunk. * A stale chunk will always be smaller than a regular chunk. * That doesn't mean there aren't any other scheduled entities for processing * That doesn't mean there aren't any other scheduled entities for processing private function rescheduleThrottledEntities(SelectionList $selectionList): void private function rescheduleThrottledEntities(SelectionList $selectionList): void { { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $groups = $selectionList->getEntityListGroups(); $this->updateTarget, foreach ($groups as $eachGroup) { $selectionList->getNormalPriorityEntityId() $groupEntityIds = $selectionList->getEntityListItemsByGroup($eachGroup); ); if (! empty($groupEntityIds)) { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $this->updateTarget, entityType: $this->updateTarget, $selectionList->getHighPriorityEntityIds(), entityIds: $groupEntityIds, true priority: QueuePriorityEnum::tryFromString($eachGroup) ); ); } } } } } } app/Console/Commands/Elasticsearch/AsyncUpdateEsEntities.php +9-3Lines changed: 9 additions & 3 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Illuminate\\Support\\Str; use Illuminate\\Support\\Str; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Component\\ES\\UpdateProcessManager; use Jiminny\\Component\\ES\\UpdateProcessManager; use Jiminny\\Exceptions\\InvalidArgumentException; use Jiminny\\Exceptions\\InvalidArgumentException; use Jiminny\\Traits\\GracefullyStoppable; use Jiminny\\Traits\\GracefullyStoppable; Redis::set($gaugeLockName, true); Redis::set($gaugeLockName, true); Redis::expire($gaugeLockName, 60); Redis::expire($gaugeLockName, 60); $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::HIGH), ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update', $updateTarget), stat: sprintf('jiminny.%s-for-update', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::NORMAL), ); ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), stat: sprintf('jiminny.%s-for-update-low', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, true), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::LOW), ); ); } } app/Console/Commands/Elasticsearch/ResetAsyncElasticSearchCommand.php +5-1Lines changed: 5 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder; use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder; use Jiminny\\Component\\ES\\Processor\\Traits\\ValidateUpdateTargetTrait; use Jiminny\\Component\\ES\\Processor\\Traits\\ValidateUpdateTargetTrait; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Component\\ES\\Repositories\\EsResetRepositoryInterface; use Jiminny\\Component\\ES\\Repositories\\EsResetRepositoryInterface; use Jiminny\\Exceptions\\InvalidArgumentException; use Jiminny\\Exceptions\\InvalidArgumentException; use Jiminny\\Traits\\GracefullyStoppable; use Jiminny\\Traits\\GracefullyStoppable; private function getRemainingScheduledEntities(bool $printStatus = false): int private function getRemainingScheduledEntities(bool $printStatus = false): int { { $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget, true); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount( $this->updateTarget, QueuePriorityEnum::HIGH ); if ($printStatus) { if ($printStatus) { $this->line( $this->line(","depth":21,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"You said","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app/Component/ES/Listeners/UpdateMultipleTargetsListener.php","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"+2-1Lines changed: 2 additions & 1 deletion","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\\Component\\ES\\Listeners;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"namespace Jiminny\\Component\\ES\\Listeners;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\QueuePriorityEnum;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Contracts\\ES\\Events\\UpdateMultipleEntities;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Contracts\\ES\\Events\\UpdateMultipleEntities;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Psr\\Log\\LoggerInterface;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Psr\\Log\\LoggerInterface;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getUpdateTargetValue(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getUpdateTargetValue(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getEntities(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getEntities(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->isPriority()","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL,","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":");","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":");","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app/Component/ES/Listeners/UpdateSingleTargetListener.php","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"+9-1Lines changed: 9 additions & 1 deletion","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Actions\\TrackElasticSearchOperations;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Actions\\TrackElasticSearchOperations;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\QueuePriorityEnum;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Contracts\\ES\\Events\\UpdateSingleEntity;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Contracts\\ES\\Events\\UpdateSingleEntity;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Psr\\Log\\LoggerInterface;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Psr\\Log\\LoggerInterface;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"'entityId' => $event->getEntityId(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"'entityId' => $event->getEntityId(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"]);","depth":23,"bounds":{"left":0.20578457,"top":0.0,"width":0.0051529254,"height":0.016360734},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"]);","depth":23,"bounds":{"left":0.20578457,"top":0.0,"width":0.0051529254,"height":0.016360734},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/**","depth":23,"bounds":{"left":0.20578457,"top":0.024740623,"width":0.0066489363,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* @important:","depth":23,"bounds":{"left":0.20578457,"top":0.08220271,"width":0.03374335,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* Synchronous event should eventually be deprecated.","depth":23,"bounds":{"left":0.20578457,"top":0.1396648,"width":0.13131648,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* Instant write operations are blocking and should be used sparingly.","depth":23,"bounds":{"left":0.20578457,"top":0.1971269,"width":0.12732713,"height":0.035514764},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* It is much better in terms of performance to write 100 or 1000 documents at once,","depth":23,"bounds":{"left":0.20578457,"top":0.273743,"width":0.13314494,"height":0.035514764},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* and have one blocking reindex operation, instead of writing 10 documents synchronously.","depth":23,"bounds":{"left":0.20578457,"top":0.35035914,"width":0.12865691,"height":0.035514764},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"*/","depth":23,"bounds":{"left":0.20578457,"top":0.42697525,"width":0.004155585,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"if ($event->isSyncEvent()) {","depth":23,"bounds":{"left":0.20578457,"top":0.4461293,"width":0.065990694,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"if ($event->isSyncEvent()) {","depth":23,"bounds":{"left":0.20578457,"top":0.46528333,"width":0.065990694,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$this->handleSyncEvent($event);","depth":23,"bounds":{"left":0.20578457,"top":0.48443735,"width":0.08028591,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$this->handleSyncEvent($event);","depth":23,"bounds":{"left":0.20578457,"top":0.50359136,"width":0.08028591,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AsyncUpdateElasticSearch::markEntityForUpdate(","depth":23,"bounds":{"left":0.20578457,"top":0.56105345,"width":0.12117686,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AsyncUpdateElasticSearch::markEntityForUpdate(","depth":23,"bounds":{"left":0.20578457,"top":0.5802075,"width":0.12117686,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getUpdateTargetValue(),","depth":23,"bounds":{"left":0.20578457,"top":0.59936154,"width":0.0809508,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getUpdateTargetValue(),","depth":23,"bounds":{"left":0.20578457,"top":0.61851555,"width":0.0809508,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getEntityId(),","depth":23,"bounds":{"left":0.20578457,"top":0.63766956,"width":0.053025264,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getEntityId(),","depth":23,"bounds":{"left":0.20578457,"top":0.65682364,"width":0.053025264,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->isPriority()","depth":23,"bounds":{"left":0.20578457,"top":0.67597765,"width":0.046708778,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL,","depth":23,"bounds":{"left":0.20578457,"top":0.69513166,"width":0.11702128,"height":0.035514764},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":");","depth":23,"bounds":{"left":0.20578457,"top":0.73343974,"width":0.0033244682,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":");","depth":23,"bounds":{"left":0.20578457,"top":0.75259376,"width":0.0033244682,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"bounds":{"left":0.20578457,"top":0.7717478,"width":0.0019946808,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"bounds":{"left":0.20578457,"top":0.79090184,"width":0.0019946808,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app/Component/ES/Processor/Actions/UpsertDocumentsAction.php","depth":23,"bounds":{"left":0.20578457,"top":0.84836394,"width":0.09375,"height":0.035514764},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"+2-1Lines changed: 2 additions & 1 deletion","depth":23,"bounds":{"left":0.20578457,"top":0.90582603,"width":0.10388963,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Processor\\DTOs\\SimpleCollection;","depth":23,"bounds":{"left":0.20578457,"top":0.94413406,"width":0.1356383,"height":0.055865943},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\DTOs\\SimpleCollection;","depth":23,"bounds":{"left":0.20578457,"top":1.0,"width":0.1356383,"height":-0.020750165},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\ResponseEvaluator;","depth":23,"bounds":{"left":0.20578457,"top":1.0,"width":0.13115026,"height":-0.07821226},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\ResponseEvaluator;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\QueuePriorityEnum;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Exceptions\\InvalidDataException;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Exceptions\\InvalidDataException;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Sentry\\Laravel\\Facade as Sentry;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Sentry\\Laravel\\Facade as Sentry;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AsyncUpdateElasticSearch::markEntityForUpdate(","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AsyncUpdateElasticSearch::markEntityForUpdate(","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"entityType: $this->updateTarget,","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"entityType: $this->updateTarget,","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"entityId: (int) $document->getId(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"entityId: (int) $document->getId(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"withPriority: true","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"priority: QueuePriorityEnum::HIGH,","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":");","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":");","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app/Component/ES/Processor/DTOs/SelectionList.php","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"+54-17Lines changed: 54 additions & 17 deletions","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Original file line numberOriginal file lineDiff line numberDiff line change","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"namespace Jiminny\\Component\\ES\\Processor\\DTOs;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"namespace Jiminny\\Component\\ES\\Processor\\DTOs;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\QueuePriorityEnum;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/**","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/**","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* A very basic and simple collection of entity IDs.","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* A very basic and simple collection of entity IDs.","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"*/","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"*/","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"class SelectionList","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"class SelectionList","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function __construct(","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private const int DEFAULT_CHUNK = 200;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private readonly array $priorityEntityIdList = [],","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private readonly array $normalEntityIdList = [],","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private int $chunkSize = self::DEFAULT_CHUNK;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private readonly bool $isStaleChunkSelected = false,","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private bool $isStaleChunkSelected = false;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private readonly int $chunkSize = 200,","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private array $selectedEntityIds = [];","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":") {","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"// Do nothing","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function setChunkSize(int $chunkSize): void","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$this->chunkSize = $chunkSize;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function getAllIds(): array","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function markStale(): void","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"return array_merge($this->priorityEntityIdList, $this->normalEntityIdList);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$this->isStaleChunkSelected = true;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function count(): int","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function addEntityList(string|QueuePriorityEnum $priority, array $entityIds): void","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"return count($this->priorityEntityIdList) + count($this->normalEntityIdList);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$priorityKey = $this->normalisePriority($priority);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"if (! array_key_exists($priorityKey, $this->selectedEntityIds)) {","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$this->selectedEntityIds[$priorityKey] = [];","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$this->selectedEntityIds[$priorityKey] = array_merge($this->selectedEntityIds[$priorityKey], $entityIds);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function isEmpty(): bool","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/**","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* @return string[]","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"*/","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function getEntityListGroups(): array","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"return empty($this->priorityEntityIdList) && empty($this->normalEntityIdList);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"return array_keys($this->selectedEntityIds);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function getHighPriorityEntityIds(): array","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function getEntityListItemsByGroup(string|QueuePriorityEnum $priority): array","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"return $this->priorityEntityIdList;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$priorityKey = $this->normalisePriority($priority);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"return $this->selectedEntityIds[$priorityKey] ?? [];","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function getNormalPriorityEntityId(): array","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function getAllIds(): array","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"return $this->normalEntityIdList;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$allIds = [];","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"foreach ($this->selectedEntityIds as $entityIds) {","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$allIds = array_merge($allIds, $entityIds);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"return $allIds;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function count(): int","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"return array_sum(","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"array_map('count', $this->selectedEntityIds)","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":");","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function isEmpty(): bool","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"return $this->count() === 0;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function isStaleChunkSelected(): bool","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function isStaleChunkSelected(): bool","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"return $this->count() >= $this->chunkSize;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"return $this->count() >= $this->chunkSize;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private function normalisePriority(string|QueuePriorityEnum $priority): string","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"return $priority instanceof QueuePriorityEnum ? $priority->value : $priority;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app/Component/ES/Processor/Traits/SelectEntityListTrait.php","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"+27-4Lines changed: 27 additions & 4 deletions","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Original file line numberOriginal file lineDiff line numberDiff line change","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Illuminate\\Support\\Facades\\Log;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Illuminate\\Support\\Facades\\Log;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\UpdateTarget;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\UpdateTarget;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\QueuePriorityEnum;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Exceptions\\InvalidArgumentException;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Exceptions\\InvalidArgumentException;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/**","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/**","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* Build the correct source list name for the type of entity and priority","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* Build the correct source list name for the type of entity and priority","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"*/","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"*/","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"trait SelectEntityListTrait","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"trait SelectEntityListTrait","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/**","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* Highest priority queue for data requiring near-instant availability.","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"}]...
|
6223598422877528678
|
-1145577539136185186
|
visual_change
|
accessibility
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
Close tab
New Tab
Customize sidebar
Close Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
AI Chat settings
Close
WORK, Google Account: [EMAIL]
Main menu
New chat
Gemini
New Chat
Open menu for conversation actions.
Conversation with Gemini
Conversation with Gemini
Show the uploaded image in a lightbox
Copy prompt
You said Make a PR of changes Find potential issues and bottlenecks
You said
Make a PR of changes Find potential issues and bottlenecks
Listen
Show thinking
Gemini said
Gemini said
I can see you've uploaded a screenshot of a code diff, likely from a version control system given the red and green highlights. I would love to help you review the changes, spot bottlenecks, and help you draft a Pull Request.
However,
the image resolution is far too low for me to read.
It appears to be a completely zoomed-out view where the code has been reduced to tiny, illegible pixels. Because of this, I cannot extract any text or logic to analyze.
How You Can Share the Code
How You Can Share the Code
To help me review your code effectively, please try one of the following:
Paste the text directly:
Copy the specific code blocks (both the old and new versions if possible) and paste them directly into our chat.
Upload the files:
If the changes are extensive, you can upload the raw text or code files.
Take high-resolution screenshots:
If you must use images, take closer, readable screenshots of the specific functions or methods you want me to review.
Once you provide the readable code, I can dive right in to identify potential bugs, assess performance bottlenecks, and help you summarize the changes for your PR!
Good response
Bad response
Share & export
Copy
Show more options
Copy prompt
Edit
You said app/Component/ES/Listeners/UpdateMultipleTargetsListener.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\Component\ES\Listeners; namespace Jiminny\Component\ES\Listeners; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Contracts\ES\Events\UpdateMultipleEntities; use Jiminny\Contracts\ES\Events\UpdateMultipleEntities; use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface; AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntities(), $event->getEntities(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } } } app/Component/ES/Listeners/UpdateSingleTargetListener.php +9-1Lines changed: 9 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Actions\TrackElasticSearchOperations; use Jiminny\Component\ES\Actions\TrackElasticSearchOperations; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Contracts\ES\Events\UpdateSingleEntity; use Jiminny\Contracts\ES\Events\UpdateSingleEntity; use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface; 'entityId' => $event->getEntityId(), 'entityId' => $event->getEntityId(), ]); ]); /** * @important: * Synchronous event should eventually be deprecated. * Instant write operations are blocking and should be used sparingly. * It is much better in terms of performance to write 100 or 1000 documents at once, * and have one blocking reindex operation, instead of writing 10 documents synchronously. */ if ($event->isSyncEvent()) { if ($event->isSyncEvent()) { $this->handleSyncEvent($event); $this->handleSyncEvent($event); AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntityId(), $event->getEntityId(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } app/Component/ES/Processor/Actions/UpsertDocumentsAction.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SimpleCollection; use Jiminny\Component\ES\Processor\DTOs\SimpleCollection; use Jiminny\Component\ES\Processor\ResponseEvaluator; use Jiminny\Component\ES\Processor\ResponseEvaluator; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Exceptions\InvalidDataException; use Jiminny\Exceptions\InvalidDataException; use Sentry\Laravel\Facade as Sentry; use Sentry\Laravel\Facade as Sentry; AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( entityType: $this->updateTarget, entityType: $this->updateTarget, entityId: (int) $document->getId(), entityId: (int) $document->getId(), withPriority: true priority: QueuePriorityEnum::HIGH, ); ); } } app/Component/ES/Processor/DTOs/SelectionList.php +54-17Lines changed: 54 additions & 17 deletions Original file line numberOriginal file lineDiff line numberDiff line change namespace Jiminny\Component\ES\Processor\DTOs; namespace Jiminny\Component\ES\Processor\DTOs; use Jiminny\Component\ES\QueuePriorityEnum; /** /** * A very basic and simple collection of entity IDs. * A very basic and simple collection of entity IDs. */ */ class SelectionList class SelectionList { { public function __construct( private const int DEFAULT_CHUNK = 200; private readonly array $priorityEntityIdList = [], private readonly array $normalEntityIdList = [], private int $chunkSize = self::DEFAULT_CHUNK; private readonly bool $isStaleChunkSelected = false, private bool $isStaleChunkSelected = false; private readonly int $chunkSize = 200, private array $selectedEntityIds = []; ) { // Do nothing public function setChunkSize(int $chunkSize): void { $this->chunkSize = $chunkSize; } } public function getAllIds(): array public function markStale(): void { { return array_merge($this->priorityEntityIdList, $this->normalEntityIdList); $this->isStaleChunkSelected = true; } } public function count(): int public function addEntityList(string|QueuePriorityEnum $priority, array $entityIds): void { { return count($this->priorityEntityIdList) + count($this->normalEntityIdList); $priorityKey = $this->normalisePriority($priority); if (! array_key_exists($priorityKey, $this->selectedEntityIds)) { $this->selectedEntityIds[$priorityKey] = []; } $this->selectedEntityIds[$priorityKey] = array_merge($this->selectedEntityIds[$priorityKey], $entityIds); } } public function isEmpty(): bool /** * @return string[] */ public function getEntityListGroups(): array { { return empty($this->priorityEntityIdList) && empty($this->normalEntityIdList); return array_keys($this->selectedEntityIds); } } public function getHighPriorityEntityIds(): array public function getEntityListItemsByGroup(string|QueuePriorityEnum $priority): array { { return $this->priorityEntityIdList; $priorityKey = $this->normalisePriority($priority); return $this->selectedEntityIds[$priorityKey] ?? []; } } public function getNormalPriorityEntityId(): array public function getAllIds(): array { { return $this->normalEntityIdList; $allIds = []; foreach ($this->selectedEntityIds as $entityIds) { $allIds = array_merge($allIds, $entityIds); } return $allIds; } public function count(): int { return array_sum( array_map('count', $this->selectedEntityIds) ); } public function isEmpty(): bool { return $this->count() === 0; } } public function isStaleChunkSelected(): bool public function isStaleChunkSelected(): bool { { return $this->count() >= $this->chunkSize; return $this->count() >= $this->chunkSize; } } private function normalisePriority(string|QueuePriorityEnum $priority): string { return $priority instanceof QueuePriorityEnum ? $priority->value : $priority; } } } app/Component/ES/Processor/Traits/SelectEntityListTrait.php +27-4Lines changed: 27 additions & 4 deletions Original file line numberOriginal file lineDiff line numberDiff line change use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; /** /** * Build the correct source list name for the type of entity and priority * Build the correct source list name for the type of entity and priority */ */ trait SelectEntityListTrait trait SelectEntityListTrait { { /** * Highest priority queue for data requiring near-instant availability. * Very few entities should be added here, only when absolutely necessary. */ private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; /** * Normal priority queue for normal application operations. * Almost all update events should pass through this queue */ private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; protected static function selectTargetList(string $entityType, bool $withPriority = false): string /** { * Nonblocking low priority queue. This queue will be consumed only when there is nothing * with higher priority. * * This queue will be used for operations such as es:reset-async */ private const string ENTITIES_LOW_PRIORITIES_LIST = '%s-for-update-low'; protected static function selectTargetList( string $entityType, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { if (! in_array($entityType, UpdateTarget::allowedTargets())) { if (! in_array($entityType, UpdateTarget::allowedTargets())) { throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); } } if ($withPriority) { if ($priority->isHigh()) { Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); } } if ($priority->isLow()) { return sprintf(self::ENTITIES_LOW_PRIORITIES_LIST, $entityType); } return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); } } } } app/Component/ES/Processor/TargetEntitiesSelector.php +26-21Lines changed: 26 additions & 21 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SelectionList; use Jiminny\Component\ES\Processor\DTOs\SelectionList; use Jiminny\Component\ES\Processor\Traits\ExtractIdsTrait; use Jiminny\Component\ES\Processor\Traits\ExtractIdsTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\QueuePriorityEnum; /** /** * This class supplies a list of entities pending an update. * This class supplies a list of entities pending an update. public function select(): SelectionList public function select(): SelectionList { { $staleWorkEntityIds = $this->getStaleChunk(); $selectionList = new SelectionList(); $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $staleWorkEntityIds = $this->getStaleChunk(); if (count($staleWorkEntityIds) > 0) { if (count($staleWorkEntityIds) > 0) { return new SelectionList( /** priorityEntityIdList: $staleWorkEntityIds, * Stale chunks are treated as high priority isStaleChunkSelected: true, */ chunkSize: ChunkSize::getStaleChunkSize($this->updateTarget), $selectionList->markStale(); ); $selectionList->addEntityList(QueuePriorityEnum::HIGH, $staleWorkEntityIds); $selectionList->setChunkSize(ChunkSize::getStaleChunkSize($this->updateTarget)); return $selectionList; } } $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $selectionList->setChunkSize($mainChunkSize); $priorityEntityIdsList = $this->extractIdsFromSet( $priorityEntityIdsList = $this->extractIds(QueuePriorityEnum::HIGH, $mainChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, true), $selectionList->addEntityList(QueuePriorityEnum::HIGH, $priorityEntityIdsList); $mainChunkSize, ); $normalEntityIdsList = []; $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); if ($normalEntityChunkSize > 0) { if ($normalEntityChunkSize > 0) { $normalEntityIdsList = $this->extractIdsFromSet( $normalEntityIdsList = $this->extractIds(QueuePriorityEnum::NORMAL, $normalEntityChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, false), $selectionList->addEntityList(QueuePriorityEnum::NORMAL, $normalEntityIdsList); $normalEntityChunkSize ); } } return new SelectionList( return $selectionList; priorityEntityIdList: $priorityEntityIdsList, normalEntityIdList: $normalEntityIdsList, chunkSize: $mainChunkSize ); } } private function getStaleChunk(): array private function getStaleChunk(): array return []; return []; } } private function extractIds(QueuePriorityEnum $priority, int $chunkSize): array { return $this->extractIdsFromSet( AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, $priority), $chunkSize ); } } } app/Component/ES/AsyncUpdateElasticSearch.php +17-10Lines changed: 17 additions & 10 deletions Original file line numberOriginal file lineDiff line numberDiff line change * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * and other activity related data * and other activity related data */ */ public static function markEntityForUpdate(string $entityType, int $entityId, bool $withPriority = false): void public static function markEntityForUpdate( { string $entityType, $targetList = self::selectTargetList($entityType, $withPriority); int $entityId, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { $targetList = self::selectTargetList($entityType, $priority); Redis::sadd($targetList, $entityId); Redis::sadd($targetList, $entityId); Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ 'entityType' => $entityType, 'entityType' => $entityType, 'entityId' => $entityId, 'entityId' => $entityId, 'collectionKey' => $targetList, 'collectionKey' => $targetList, 'withPriority' => $withPriority, 'priority' => $priority->value, ]); ]); } } public static function bulkMarkEntitiesForUpdate( public static function bulkMarkEntitiesForUpdate( string $entityType, string $entityType, array $entityIds, array $entityIds, bool $withPriority = false QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { ): void { if (empty($entityIds)) { if (empty($entityIds)) { return; return; } } $targetList = self::selectTargetList($entityType, $withPriority); $targetList = self::selectTargetList($entityType, $priority); Redis::saddarray($targetList, $entityIds); Redis::saddarray($targetList, $entityIds); } } * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Takes priority into consideration. * Takes priority into consideration. */ */ public static function getEntitiesSourceList(string $updateTarget, $priority = false): string public static function getEntitiesSourceList( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { return self::selectTargetList($updateTarget, $priority); return self::selectTargetList($updateTarget, $priority); } } /** /** * Externally called helper methods * Externally called helper methods * - count and flush * - count and flush */ */ public static function getEntitiesListCount(string $updateTarget, $priority = false): int public static function getEntitiesListCount( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): int { $targetList = self::selectTargetList($updateTarget, $priority); $targetList = self::selectTargetList($updateTarget, $priority); return Redis::scard($targetList); return Redis::scard($targetList); app/Component/ES/QueuePriorityEnum.php +40Lines changed: 40 additions & 0 deletions Original file line numberOriginal file lineDiff line numberDiff line change <?php declare(strict_types=1); namespace Jiminny\Component\ES; use Jiminny\Exceptions\InvalidArgumentException; enum QueuePriorityEnum: string { case HIGH = 'high'; case NORMAL = 'normal'; case LOW = 'low'; public static function tryFromString(string $value): self { if (! self::isValid($value)) { throw new InvalidArgumentException( sprintf('Invalid queue priority "%s" selected', $value) ); } return self::tryFrom($value); } public static function isValid(string $value): bool { return self::tryFrom($value) !== null; } public function isLow(): bool { return $this === self::LOW; } public function isHigh(): bool { return $this === self::HIGH; } } app/Component/ES/UpdateProcessManager.php +12-9Lines changed: 12 additions & 9 deletions Original file line numberOriginal file lineDiff line numberDiff line change if ($selectionList->isEmpty()) { if ($selectionList->isEmpty()) { return false; return false; } } /** /** * A stale chunk will always be smaller than a regular chunk. * A stale chunk will always be smaller than a regular chunk. * That doesn't mean there aren't any other scheduled entities for processing * That doesn't mean there aren't any other scheduled entities for processing private function rescheduleThrottledEntities(SelectionList $selectionList): void private function rescheduleThrottledEntities(SelectionList $selectionList): void { { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $groups = $selectionList->getEntityListGroups(); $this->updateTarget, foreach ($groups as $eachGroup) { $selectionList->getNormalPriorityEntityId() $groupEntityIds = $selectionList->getEntityListItemsByGroup($eachGroup); ); if (! empty($groupEntityIds)) { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $this->updateTarget, entityType: $this->updateTarget, $selectionList->getHighPriorityEntityIds(), entityIds: $groupEntityIds, true priority: QueuePriorityEnum::tryFromString($eachGroup) ); ); } } } } } } app/Console/Commands/Elasticsearch/AsyncUpdateEsEntities.php +9-3Lines changed: 9 additions & 3 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Illuminate\Support\Str; use Illuminate\Support\Str; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Component\ES\UpdateProcessManager; use Jiminny\Component\ES\UpdateProcessManager; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Traits\GracefullyStoppable; use Jiminny\Traits\GracefullyStoppable; Redis::set($gaugeLockName, true); Redis::set($gaugeLockName, true); Redis::expire($gaugeLockName, 60); Redis::expire($gaugeLockName, 60); $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::HIGH), ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update', $updateTarget), stat: sprintf('jiminny.%s-for-update', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::NORMAL), ); ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), stat: sprintf('jiminny.%s-for-update-low', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, true), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::LOW), ); ); } } app/Console/Commands/Elasticsearch/ResetAsyncElasticSearchCommand.php +5-1Lines changed: 5 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\Traits\ValidateUpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\ValidateUpdateTargetTrait; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Component\ES\Repositories\EsResetRepositoryInterface; use Jiminny\Component\ES\Repositories\EsResetRepositoryInterface; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Traits\GracefullyStoppable; use Jiminny\Traits\GracefullyStoppable; private function getRemainingScheduledEntities(bool $printStatus = false): int private function getRemainingScheduledEntities(bool $printStatus = false): int { { $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget, true); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount( $this->updateTarget, QueuePriorityEnum::HIGH ); if ($printStatus) { if ($printStatus) { $this->line( $this->line(
You said
app/Component/ES/Listeners/UpdateMultipleTargetsListener.php
+2-1Lines changed: 2 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\Component\ES\Listeners;
namespace Jiminny\Component\ES\Listeners;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\QueuePriorityEnum;
use Jiminny\Contracts\ES\Events\UpdateMultipleEntities;
use Jiminny\Contracts\ES\Events\UpdateMultipleEntities;
use Psr\Log\LoggerInterface;
use Psr\Log\LoggerInterface;
AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(
AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(
$event->getUpdateTargetValue(),
$event->getUpdateTargetValue(),
$event->getEntities(),
$event->getEntities(),
$event->isPriority()
$event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL,
);
);
}
}
}
}
app/Component/ES/Listeners/UpdateSingleTargetListener.php
+9-1Lines changed: 9 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Actions\TrackElasticSearchOperations;
use Jiminny\Component\ES\Actions\TrackElasticSearchOperations;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\Processor\EntityQueryBuilder;
use Jiminny\Component\ES\Processor\EntityQueryBuilder;
use Jiminny\Component\ES\QueuePriorityEnum;
use Jiminny\Contracts\ES\Events\UpdateSingleEntity;
use Jiminny\Contracts\ES\Events\UpdateSingleEntity;
use Psr\Log\LoggerInterface;
use Psr\Log\LoggerInterface;
'entityId' => $event->getEntityId(),
'entityId' => $event->getEntityId(),
]);
]);
/**
* @important:
* Synchronous event should eventually be deprecated.
* Instant write operations are blocking and should be used sparingly.
* It is much better in terms of performance to write 100 or 1000 documents at once,
* and have one blocking reindex operation, instead of writing 10 documents synchronously.
*/
if ($event->isSyncEvent()) {
if ($event->isSyncEvent()) {
$this->handleSyncEvent($event);
$this->handleSyncEvent($event);
AsyncUpdateElasticSearch::markEntityForUpdate(
AsyncUpdateElasticSearch::markEntityForUpdate(
$event->getUpdateTargetValue(),
$event->getUpdateTargetValue(),
$event->getEntityId(),
$event->getEntityId(),
$event->isPriority()
$event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL,
);
);
}
}
app/Component/ES/Processor/Actions/UpsertDocumentsAction.php
+2-1Lines changed: 2 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SimpleCollection;
use Jiminny\Component\ES\Processor\DTOs\SimpleCollection;
use Jiminny\Component\ES\Processor\ResponseEvaluator;
use Jiminny\Component\ES\Processor\ResponseEvaluator;
use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait;
use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait;
use Jiminny\Component\ES\QueuePriorityEnum;
use Jiminny\Exceptions\InvalidDataException;
use Jiminny\Exceptions\InvalidDataException;
use Sentry\Laravel\Facade as Sentry;
use Sentry\Laravel\Facade as Sentry;
AsyncUpdateElasticSearch::markEntityForUpdate(
AsyncUpdateElasticSearch::markEntityForUpdate(
entityType: $this->updateTarget,
entityType: $this->updateTarget,
entityId: (int) $document->getId(),
entityId: (int) $document->getId(),
withPriority: true
priority: QueuePriorityEnum::HIGH,
);
);
}
}
app/Component/ES/Processor/DTOs/SelectionList.php
+54-17Lines changed: 54 additions & 17 deletions
Original file line numberOriginal file lineDiff line numberDiff line change
namespace Jiminny\Component\ES\Processor\DTOs;
namespace Jiminny\Component\ES\Processor\DTOs;
use Jiminny\Component\ES\QueuePriorityEnum;
/**
/**
* A very basic and simple collection of entity IDs.
* A very basic and simple collection of entity IDs.
*/
*/
class SelectionList
class SelectionList
{
{
public function __construct(
private const int DEFAULT_CHUNK = 200;
private readonly array $priorityEntityIdList = [],
private readonly array $normalEntityIdList = [],
private int $chunkSize = self::DEFAULT_CHUNK;
private readonly bool $isStaleChunkSelected = false,
private bool $isStaleChunkSelected = false;
private readonly int $chunkSize = 200,
private array $selectedEntityIds = [];
) {
// Do nothing
public function setChunkSize(int $chunkSize): void
{
$this->chunkSize = $chunkSize;
}
}
public function getAllIds(): array
public function markStale(): void
{
{
return array_merge($this->priorityEntityIdList, $this->normalEntityIdList);
$this->isStaleChunkSelected = true;
}
}
public function count(): int
public function addEntityList(string|QueuePriorityEnum $priority, array $entityIds): void
{
{
return count($this->priorityEntityIdList) + count($this->normalEntityIdList);
$priorityKey = $this->normalisePriority($priority);
if (! array_key_exists($priorityKey, $this->selectedEntityIds)) {
$this->selectedEntityIds[$priorityKey] = [];
}
$this->selectedEntityIds[$priorityKey] = array_merge($this->selectedEntityIds[$priorityKey], $entityIds);
}
}
public function isEmpty(): bool
/**
* @return string[]
*/
public function getEntityListGroups(): array
{
{
return empty($this->priorityEntityIdList) && empty($this->normalEntityIdList);
return array_keys($this->selectedEntityIds);
}
}
public function getHighPriorityEntityIds(): array
public function getEntityListItemsByGroup(string|QueuePriorityEnum $priority): array
{
{
return $this->priorityEntityIdList;
$priorityKey = $this->normalisePriority($priority);
return $this->selectedEntityIds[$priorityKey] ?? [];
}
}
public function getNormalPriorityEntityId(): array
public function getAllIds(): array
{
{
return $this->normalEntityIdList;
$allIds = [];
foreach ($this->selectedEntityIds as $entityIds) {
$allIds = array_merge($allIds, $entityIds);
}
return $allIds;
}
public function count(): int
{
return array_sum(
array_map('count', $this->selectedEntityIds)
);
}
public function isEmpty(): bool
{
return $this->count() === 0;
}
}
public function isStaleChunkSelected(): bool
public function isStaleChunkSelected(): bool
{
{
return $this->count() >= $this->chunkSize;
return $this->count() >= $this->chunkSize;
}
}
private function normalisePriority(string|QueuePriorityEnum $priority): string
{
return $priority instanceof QueuePriorityEnum ? $priority->value : $priority;
}
}
}
app/Component/ES/Processor/Traits/SelectEntityListTrait.php
+27-4Lines changed: 27 additions & 4 deletions
Original file line numberOriginal file lineDiff line numberDiff line change
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Log;
use Jiminny\Component\ES\Processor\UpdateTarget;
use Jiminny\Component\ES\Processor\UpdateTarget;
use Jiminny\Component\ES\QueuePriorityEnum;
use Jiminny\Exceptions\InvalidArgumentException;
use Jiminny\Exceptions\InvalidArgumentException;
/**
/**
* Build the correct source list name for the type of entity and priority
* Build the correct source list name for the type of entity and priority
*/
*/
trait SelectEntityListTrait
trait SelectEntityListTrait
{
{
/**
* Highest priority queue for data requiring near-instant availability....
|
55698
|
NULL
|
NULL
|
NULL
|
|
55701
|
1935
|
3
|
2026-05-19T06:42:58.699432+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779172978699_m2.jpg...
|
Firefox
|
JY-20808 low priority indexing queue by Vasil-Jimi JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app — Work...
|
1
|
github.com/jiminny/app/pull/12082/changes#diff-49a github.com/jiminny/app/pull/12082/changes#diff-49a79d99c97caf7fc27ecb1dbacab5a29d871822caa0db0c71e94957c28c87af...
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
Close tab
New Tab
Customize sidebar
Close Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
AI Chat settings
Close
WORK, Google Account: [EMAIL]
Main menu
New chat
Gemini
New Chat
Open menu for conversation actions.
Conversation with Gemini
Conversation with Gemini
Show the uploaded image in a lightbox
Copy prompt
You said Make a PR of changes Find potential issues and bottlenecks
You said
Make a PR of changes Find potential issues and bottlenecks
Listen
Show thinking
Gemini said
Gemini said
I can see you've uploaded a screenshot of a code diff, likely from a version control system given the red and green highlights. I would love to help you review the changes, spot bottlenecks, and help you draft a Pull Request.
However,
the image resolution is far too low for me to read.
It appears to be a completely zoomed-out view where the code has been reduced to tiny, illegible pixels. Because of this, I cannot extract any text or logic to analyze.
How You Can Share the Code
How You Can Share the Code
To help me review your code effectively, please try one of the following:
Paste the text directly:
Copy the specific code blocks (both the old and new versions if possible) and paste them directly into our chat.
Upload the files:
If the changes are extensive, you can upload the raw text or code files.
Take high-resolution screenshots:
If you must use images, take closer, readable screenshots of the specific functions or methods you want me to review.
Once you provide the readable code, I can dive right in to identify potential bugs, assess performance bottlenecks, and help you summarize the changes for your PR!
Good response
Bad response
Share & export
Copy
Show more options
Copy prompt
Edit
You said app/Component/ES/Listeners/UpdateMultipleTargetsListener.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\Component\ES\Listeners; namespace Jiminny\Component\ES\Listeners; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Contracts\ES\Events\UpdateMultipleEntities; use Jiminny\Contracts\ES\Events\UpdateMultipleEntities; use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface; AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntities(), $event->getEntities(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } } } app/Component/ES/Listeners/UpdateSingleTargetListener.php +9-1Lines changed: 9 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Actions\TrackElasticSearchOperations; use Jiminny\Component\ES\Actions\TrackElasticSearchOperations; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Contracts\ES\Events\UpdateSingleEntity; use Jiminny\Contracts\ES\Events\UpdateSingleEntity; use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface; 'entityId' => $event->getEntityId(), 'entityId' => $event->getEntityId(), ]); ]); /** * @important: * Synchronous event should eventually be deprecated. * Instant write operations are blocking and should be used sparingly. * It is much better in terms of performance to write 100 or 1000 documents at once, * and have one blocking reindex operation, instead of writing 10 documents synchronously. */ if ($event->isSyncEvent()) { if ($event->isSyncEvent()) { $this->handleSyncEvent($event); $this->handleSyncEvent($event); AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntityId(), $event->getEntityId(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } app/Component/ES/Processor/Actions/UpsertDocumentsAction.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SimpleCollection; use Jiminny\Component\ES\Processor\DTOs\SimpleCollection; use Jiminny\Component\ES\Processor\ResponseEvaluator; use Jiminny\Component\ES\Processor\ResponseEvaluator; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Exceptions\InvalidDataException; use Jiminny\Exceptions\InvalidDataException; use Sentry\Laravel\Facade as Sentry; use Sentry\Laravel\Facade as Sentry; AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( entityType: $this->updateTarget, entityType: $this->updateTarget, entityId: (int) $document->getId(), entityId: (int) $document->getId(), withPriority: true priority: QueuePriorityEnum::HIGH, ); ); } } app/Component/ES/Processor/DTOs/SelectionList.php +54-17Lines changed: 54 additions & 17 deletions Original file line numberOriginal file lineDiff line numberDiff line change namespace Jiminny\Component\ES\Processor\DTOs; namespace Jiminny\Component\ES\Processor\DTOs; use Jiminny\Component\ES\QueuePriorityEnum; /** /** * A very basic and simple collection of entity IDs. * A very basic and simple collection of entity IDs. */ */ class SelectionList class SelectionList { { public function __construct( private const int DEFAULT_CHUNK = 200; private readonly array $priorityEntityIdList = [], private readonly array $normalEntityIdList = [], private int $chunkSize = self::DEFAULT_CHUNK; private readonly bool $isStaleChunkSelected = false, private bool $isStaleChunkSelected = false; private readonly int $chunkSize = 200, private array $selectedEntityIds = []; ) { // Do nothing public function setChunkSize(int $chunkSize): void { $this->chunkSize = $chunkSize; } } public function getAllIds(): array public function markStale(): void { { return array_merge($this->priorityEntityIdList, $this->normalEntityIdList); $this->isStaleChunkSelected = true; } } public function count(): int public function addEntityList(string|QueuePriorityEnum $priority, array $entityIds): void { { return count($this->priorityEntityIdList) + count($this->normalEntityIdList); $priorityKey = $this->normalisePriority($priority); if (! array_key_exists($priorityKey, $this->selectedEntityIds)) { $this->selectedEntityIds[$priorityKey] = []; } $this->selectedEntityIds[$priorityKey] = array_merge($this->selectedEntityIds[$priorityKey], $entityIds); } } public function isEmpty(): bool /** * @return string[] */ public function getEntityListGroups(): array { { return empty($this->priorityEntityIdList) && empty($this->normalEntityIdList); return array_keys($this->selectedEntityIds); } } public function getHighPriorityEntityIds(): array public function getEntityListItemsByGroup(string|QueuePriorityEnum $priority): array { { return $this->priorityEntityIdList; $priorityKey = $this->normalisePriority($priority); return $this->selectedEntityIds[$priorityKey] ?? []; } } public function getNormalPriorityEntityId(): array public function getAllIds(): array { { return $this->normalEntityIdList; $allIds = []; foreach ($this->selectedEntityIds as $entityIds) { $allIds = array_merge($allIds, $entityIds); } return $allIds; } public function count(): int { return array_sum( array_map('count', $this->selectedEntityIds) ); } public function isEmpty(): bool { return $this->count() === 0; } } public function isStaleChunkSelected(): bool public function isStaleChunkSelected(): bool { { return $this->count() >= $this->chunkSize; return $this->count() >= $this->chunkSize; } } private function normalisePriority(string|QueuePriorityEnum $priority): string { return $priority instanceof QueuePriorityEnum ? $priority->value : $priority; } } } app/Component/ES/Processor/Traits/SelectEntityListTrait.php +27-4Lines changed: 27 additions & 4 deletions Original file line numberOriginal file lineDiff line numberDiff line change use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; /** /** * Build the correct source list name for the type of entity and priority * Build the correct source list name for the type of entity and priority */ */ trait SelectEntityListTrait trait SelectEntityListTrait { { /** * Highest priority queue for data requiring near-instant availability. * Very few entities should be added here, only when absolutely necessary. */ private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; /** * Normal priority queue for normal application operations. * Almost all update events should pass through this queue */ private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; protected static function selectTargetList(string $entityType, bool $withPriority = false): string /** { * Nonblocking low priority queue. This queue will be consumed only when there is nothing * with higher priority. * * This queue will be used for operations such as es:reset-async */ private const string ENTITIES_LOW_PRIORITIES_LIST = '%s-for-update-low'; protected static function selectTargetList( string $entityType, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { if (! in_array($entityType, UpdateTarget::allowedTargets())) { if (! in_array($entityType, UpdateTarget::allowedTargets())) { throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); } } if ($withPriority) { if ($priority->isHigh()) { Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); } } if ($priority->isLow()) { return sprintf(self::ENTITIES_LOW_PRIORITIES_LIST, $entityType); } return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); } } } } app/Component/ES/Processor/TargetEntitiesSelector.php +26-21Lines changed: 26 additions & 21 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SelectionList; use Jiminny\Component\ES\Processor\DTOs\SelectionList; use Jiminny\Component\ES\Processor\Traits\ExtractIdsTrait; use Jiminny\Component\ES\Processor\Traits\ExtractIdsTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\QueuePriorityEnum; /** /** * This class supplies a list of entities pending an update. * This class supplies a list of entities pending an update. public function select(): SelectionList public function select(): SelectionList { { $staleWorkEntityIds = $this->getStaleChunk(); $selectionList = new SelectionList(); $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $staleWorkEntityIds = $this->getStaleChunk(); if (count($staleWorkEntityIds) > 0) { if (count($staleWorkEntityIds) > 0) { return new SelectionList( /** priorityEntityIdList: $staleWorkEntityIds, * Stale chunks are treated as high priority isStaleChunkSelected: true, */ chunkSize: ChunkSize::getStaleChunkSize($this->updateTarget), $selectionList->markStale(); ); $selectionList->addEntityList(QueuePriorityEnum::HIGH, $staleWorkEntityIds); $selectionList->setChunkSize(ChunkSize::getStaleChunkSize($this->updateTarget)); return $selectionList; } } $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $selectionList->setChunkSize($mainChunkSize); $priorityEntityIdsList = $this->extractIdsFromSet( $priorityEntityIdsList = $this->extractIds(QueuePriorityEnum::HIGH, $mainChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, true), $selectionList->addEntityList(QueuePriorityEnum::HIGH, $priorityEntityIdsList); $mainChunkSize, ); $normalEntityIdsList = []; $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); if ($normalEntityChunkSize > 0) { if ($normalEntityChunkSize > 0) { $normalEntityIdsList = $this->extractIdsFromSet( $normalEntityIdsList = $this->extractIds(QueuePriorityEnum::NORMAL, $normalEntityChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, false), $selectionList->addEntityList(QueuePriorityEnum::NORMAL, $normalEntityIdsList); $normalEntityChunkSize ); } } return new SelectionList( return $selectionList; priorityEntityIdList: $priorityEntityIdsList, normalEntityIdList: $normalEntityIdsList, chunkSize: $mainChunkSize ); } } private function getStaleChunk(): array private function getStaleChunk(): array return []; return []; } } private function extractIds(QueuePriorityEnum $priority, int $chunkSize): array { return $this->extractIdsFromSet( AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, $priority), $chunkSize ); } } } app/Component/ES/AsyncUpdateElasticSearch.php +17-10Lines changed: 17 additions & 10 deletions Original file line numberOriginal file lineDiff line numberDiff line change * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * and other activity related data * and other activity related data */ */ public static function markEntityForUpdate(string $entityType, int $entityId, bool $withPriority = false): void public static function markEntityForUpdate( { string $entityType, $targetList = self::selectTargetList($entityType, $withPriority); int $entityId, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { $targetList = self::selectTargetList($entityType, $priority); Redis::sadd($targetList, $entityId); Redis::sadd($targetList, $entityId); Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ 'entityType' => $entityType, 'entityType' => $entityType, 'entityId' => $entityId, 'entityId' => $entityId, 'collectionKey' => $targetList, 'collectionKey' => $targetList, 'withPriority' => $withPriority, 'priority' => $priority->value, ]); ]); } } public static function bulkMarkEntitiesForUpdate( public static function bulkMarkEntitiesForUpdate( string $entityType, string $entityType, array $entityIds, array $entityIds, bool $withPriority = false QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { ): void { if (empty($entityIds)) { if (empty($entityIds)) { return; return; } } $targetList = self::selectTargetList($entityType, $withPriority); $targetList = self::selectTargetList($entityType, $priority); Redis::saddarray($targetList, $entityIds); Redis::saddarray($targetList, $entityIds); } } * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Takes priority into consideration. * Takes priority into consideration. */ */ public static function getEntitiesSourceList(string $updateTarget, $priority = false): string public static function getEntitiesSourceList( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { return self::selectTargetList($updateTarget, $priority); return self::selectTargetList($updateTarget, $priority); } } /** /** * Externally called helper methods * Externally called helper methods * - count and flush * - count and flush */ */ public static function getEntitiesListCount(string $updateTarget, $priority = false): int public static function getEntitiesListCount( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): int { $targetList = self::selectTargetList($updateTarget, $priority); $targetList = self::selectTargetList($updateTarget, $priority); return Redis::scard($targetList); return Redis::scard($targetList); app/Component/ES/QueuePriorityEnum.php +40Lines changed: 40 additions & 0 deletions Original file line numberOriginal file lineDiff line numberDiff line change <?php declare(strict_types=1); namespace Jiminny\Component\ES; use Jiminny\Exceptions\InvalidArgumentException; enum QueuePriorityEnum: string { case HIGH = 'high'; case NORMAL = 'normal'; case LOW = 'low'; public static function tryFromString(string $value): self { if (! self::isValid($value)) { throw new InvalidArgumentException( sprintf('Invalid queue priority "%s" selected', $value) ); } return self::tryFrom($value); } public static function isValid(string $value): bool { return self::tryFrom($value) !== null; } public function isLow(): bool { return $this === self::LOW; } public function isHigh(): bool { return $this === self::HIGH; } } app/Component/ES/UpdateProcessManager.php +12-9Lines changed: 12 additions & 9 deletions Original file line numberOriginal file lineDiff line numberDiff line change if ($selectionList->isEmpty()) { if ($selectionList->isEmpty()) { return false; return false; } } /** /** * A stale chunk will always be smaller than a regular chunk. * A stale chunk will always be smaller than a regular chunk. * That doesn't mean there aren't any other scheduled entities for processing * That doesn't mean there aren't any other scheduled entities for processing private function rescheduleThrottledEntities(SelectionList $selectionList): void private function rescheduleThrottledEntities(SelectionList $selectionList): void { { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $groups = $selectionList->getEntityListGroups(); $this->updateTarget, foreach ($groups as $eachGroup) { $selectionList->getNormalPriorityEntityId() $groupEntityIds = $selectionList->getEntityListItemsByGroup($eachGroup); ); if (! empty($groupEntityIds)) { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $this->updateTarget, entityType: $this->updateTarget, $selectionList->getHighPriorityEntityIds(), entityIds: $groupEntityIds, true priority: QueuePriorityEnum::tryFromString($eachGroup) ); ); } } } } } } app/Console/Commands/Elasticsearch/AsyncUpdateEsEntities.php +9-3Lines changed: 9 additions & 3 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Illuminate\Support\Str; use Illuminate\Support\Str; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Component\ES\UpdateProcessManager; use Jiminny\Component\ES\UpdateProcessManager; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Traits\GracefullyStoppable; use Jiminny\Traits\GracefullyStoppable; Redis::set($gaugeLockName, true); Redis::set($gaugeLockName, true); Redis::expire($gaugeLockName, 60); Redis::expire($gaugeLockName, 60); $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::HIGH), ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update', $updateTarget), stat: sprintf('jiminny.%s-for-update', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::NORMAL), ); ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), stat: sprintf('jiminny.%s-for-update-low', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, true), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::LOW), ); ); } } app/Console/Commands/Elasticsearch/ResetAsyncElasticSearchCommand.php +5-1Lines changed: 5 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\Traits\ValidateUpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\ValidateUpdateTargetTrait; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Component\ES\Repositories\EsResetRepositoryInterface; use Jiminny\Component\ES\Repositories\EsResetRepositoryInterface; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Traits\GracefullyStoppable; use Jiminny\Traits\GracefullyStoppable; private function getRemainingScheduledEntities(bool $printStatus = false): int private function getRemainingScheduledEntities(bool $printStatus = false): int { { $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget, true); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount( $this->updateTarget, QueuePriorityEnum::HIGH ); if ($printStatus) { if ($printStatus) { $this->line( $this->line(
You said
app/Component/ES/Listeners/UpdateMultipleTargetsListener.php
+2-1Lines changed: 2 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\Component\ES\Listeners;
namespace Jiminny\Component\ES\Listeners;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\QueuePriorityEnum;
use Jiminny\Contracts\ES\Events\UpdateMultipleEntities;
use Jiminny\Contracts\ES\Events\UpdateMultipleEntities;
use Psr\Log\LoggerInterface;
use Psr\Log\LoggerInterface;
AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(
AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(
$event->getUpdateTargetValue(),
$event->getUpdateTargetValue(),
$event->getEntities(),
$event->getEntities(),
$event->isPriority()
$event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL,
);
);
}
}
}
}
app/Component/ES/Listeners/UpdateSingleTargetListener.php
+9-1Lines changed: 9 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Actions\TrackElasticSearchOperations;
use Jiminny\Component\ES\Actions\TrackElasticSearchOperations;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\Processor\EntityQueryBuilder;
use Jiminny\Component\ES\Processor\EntityQueryBuilder;
use Jiminny\Component\ES\QueuePriorityEnum;
use Jiminny\Contracts\ES\Events\UpdateSingleEntity;
use Jiminny\Contracts\ES\Events\UpdateSingleEntity;
use Psr\Log\LoggerInterface;
use Psr\Log\LoggerInterface;
'entityId' => $event->getEntityId(),
'entityId' => $event->getEntityId(),
]);
]);
/**
* @important:
* Synchronous event should eventually be deprecated.
* Instant write operations are blocking and should be used sparingly.
* It is much better in terms of performance to write 100 or 1000 documents at once,
* and have one blocking reindex operation, instead of writing 10 documents synchronously.
*/
if ($event->isSyncEvent()) {
if ($event->isSyncEvent()) {
$this->handleSyncEvent($event);
$this->handleSyncEvent($event);
AsyncUpdateElasticSearch::markEntityForUpdate(
AsyncUpdateElasticSearch::markEntityForUpdate(
$event->getUpdateTargetValue(),
$event->getUpdateTargetValue(),
$event->getEntityId(),
$event->getEntityId(),
$event->isPriority()
$event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL,
);
);
}
}
app/Component/ES/Processor/Actions/UpsertDocumentsAction.php
+2-1Lines changed: 2 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SimpleCollection;
use Jiminny\Component\ES\Processor\DTOs\SimpleCollection;
use Jiminny\Component\ES\Processor\ResponseEvaluator;
use Jiminny\Component\ES\Processor\ResponseEvaluator;
use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait;
use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait;
use Jiminny\Component\ES\QueuePriorityEnum;
use Jiminny\Exceptions\InvalidDataException;
use Jiminny\Exceptions\InvalidDataException;
use Sentry\Laravel\Facade as Sentry;
use Sentry\Laravel\Facade as Sentry;
AsyncUpdateElasticSearch::markEntityForUpdate(
AsyncUpdateElasticSearch::markEntityForUpdate(
entityType: $this->updateTarget,
entityType: $this->updateTarget,
entityId: (int) $document->getId(),
entityId: (int) $document->getId(),
withPriority: true
priority: QueuePriorityEnum::HIGH,
);
);
}
}
app/Component/ES/Processor/DTOs/SelectionList.php
+54-17Lines changed: 54 additions & 17 deletions
Original file line numberOriginal file lineDiff line numberDiff line change
namespace Jiminny\Component\ES\Processor\DTOs;
namespace Jiminny\Component\ES\Processor\DTOs;
use Jiminny\Component\ES\QueuePriorityEnum;
/**
/**
* A very basic and simple collection of entity IDs.
* A very basic and simple collection of entity IDs.
*/
*/
class SelectionList
class SelectionList
{
{
public function __construct(
private const int DEFAULT_CHUNK = 200;
private readonly array $priorityEntityIdList = [],
private readonly array $normalEntityIdList = [],
private int $chunkSize = self::DEFAULT_CHUNK;
private readonly bool $isStaleChunkSelected = false,
private bool $isStaleChunkSelected = false;
private readonly int $chunkSize = 200,
private array $selectedEntityIds = [];
) {
// Do nothing
public function setChunkSize(int $chunkSize): void
{
$this->chunkSize = $chunkSize;
}
}
public function getAllIds(): array
public function markStale(): void
{
{
return array_merge($this->priorityEntityIdList, $this->normalEntityIdList);
$this->isStaleChunkSelected = true;
}
}
public function count(): int
public function addEntityList(string|QueuePriorityEnum $priority, array $entityIds): void
{
{
return count($this->priorityEntityIdList) + count($this->normalEntityIdList);
$priorityKey = $this->normalisePriority($priority);
if (! array_key_exists($priorityKey, $this->selectedEntityIds)) {
$this->selectedEntityIds[$priorityKey] = [];
}
$this->selectedEntityIds[$priorityKey] = array_merge($this->selectedEntityIds[$priorityKey], $entityIds);
}
}
public function isEmpty(): bool
/**
* @return string[]
*/
public function getEntityListGroups(): array
{
{
return empty($this->priorityEntityIdList) && empty($this->normalEntityIdList);
return array_keys($this->selectedEntityIds);
}
}
public function getHighPriorityEntityIds(): array
public function getEntityListItemsByGroup(string|QueuePriorityEnum $priority): array
{
{
return $this->priorityEntityIdList;
$priorityKey = $this->normalisePriority($priority);
return $this->selectedEntityIds[$priorityKey] ?? [];
}
}
public function getNormalPriorityEntityId(): array
public function getAllIds(): array
{
{
return $this->normalEntityIdList;
$allIds = [];
foreach ($this->selectedEntityIds as $entityIds) {
$allIds = array_merge($allIds, $entityIds);
}
return $allIds;
}
public function count(): int
{
return array_sum(
array_map('count', $this->selectedEntityIds)
);
}
public function isEmpty(): bool
{
return $this->count() === 0;
}
}
public function isStaleChunkSelected(): bool
public function isStaleChunkSelected(): bool
{
{
return $this->count() >= $this->chunkSize;
return $this->count() >= $this->chunkSize;
}
}
private function normalisePriority(string|QueuePriorityEnum $priority): string
{
return $priority instanceof QueuePriorityEnum ? $priority->value : $priority;
}
}
}
app/Component/ES/Processor/Traits/SelectEntityListTrait.php
+27-4Lines changed: 27 additions & 4 deletions
Original file line numberOriginal file lineDiff line numberDiff line change
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Log;
use Jiminny\Component\ES\Processor\UpdateTarget;
use Jiminny\Component\ES\Processor\UpdateTarget;
use Jiminny\Component\ES\QueuePriorityEnum;
use Jiminny\Exceptions\InvalidArgumentException;
use Jiminny\Exceptions\InvalidArgumentException;
/**
/**
* Build the correct source list name for the type of entity and priority
* Build the correct source list name for the type of entity and priority
*/
*/
trait SelectEntityListTrait
trait SelectEntityListTrait
{
{
/**
* Highest priority queue for data requiring near-instant availability.
* Very few entities should be added here, only when absolutely necessary.
*/
private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority';
/**
* Normal priority queue for normal application operations.
* Almost all update events should pass through this queue
*/
private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update';
private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update';
private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority';
protected static function selectTargetList(string $entityType, bool $withPriority = false): string
/**
{
* Nonblocking low priority queue. This queue will be consumed only when there is nothing...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira","depth":4,"bounds":{"left":0.0,"top":0.0518755,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.06304868,"width":0.10106383,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app","depth":4,"bounds":{"left":0.0,"top":0.08459697,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app","depth":5,"bounds":{"left":0.013297873,"top":0.09577015,"width":0.18816489,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app","depth":4,"bounds":{"left":0.0,"top":0.11731844,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app","depth":5,"bounds":{"left":0.013297873,"top":0.12849163,"width":0.15674867,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.06732048,"top":0.1245012,"width":0.007978723,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New Tab","depth":4,"bounds":{"left":0.0028257978,"top":0.15163608,"width":0.07413564,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"bounds":{"left":0.0028257978,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Close Google Gemini (⌃X)","depth":6,"bounds":{"left":0.013796543,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Tabs from other devices","depth":6,"bounds":{"left":0.024933511,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"bounds":{"left":0.036070477,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"bounds":{"left":0.04720745,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"AI Chat settings","depth":7,"bounds":{"left":0.35854387,"top":0.055067837,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Close","depth":7,"bounds":{"left":0.37051198,"top":0.055067837,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"WORK, Google Account: lukas.kovalik@jiminny.com","depth":12,"bounds":{"left":0.3678524,"top":0.103751,"width":0.013297873,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Main menu","depth":12,"bounds":{"left":0.08494016,"top":0.103751,"width":0.013297873,"height":0.031923383},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New chat","depth":12,"bounds":{"left":0.09823803,"top":0.10454908,"width":0.028590426,"height":0.030327214},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Gemini","depth":15,"bounds":{"left":0.1008976,"top":0.10973663,"width":0.021941489,"height":0.020351157},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"New Chat","depth":12,"bounds":{"left":0.33992687,"top":0.103751,"width":0.013297873,"height":0.031923383},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Open menu for conversation actions.","depth":12,"bounds":{"left":0.35322472,"top":0.103751,"width":0.013297873,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXHeading","text":"Conversation with Gemini","depth":15,"bounds":{"left":0.079288565,"top":0.14764565,"width":0.0003324468,"height":0.0007980846},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Conversation with Gemini","depth":16,"bounds":{"left":0.079288565,"top":0.15003991,"width":0.1200133,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Show the uploaded image in a lightbox","depth":21,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy prompt","depth":21,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"You said Make a PR of changes Find potential issues and bottlenecks","depth":21,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"You said","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Make a PR of changes Find potential issues and bottlenecks","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Listen","depth":22,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Show thinking","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Gemini said","depth":20,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Gemini said","depth":21,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"I can see you've uploaded a screenshot of a code diff, likely from a version control system given the red and green highlights. I would love to help you review the changes, spot bottlenecks, and help you draft a Pull Request.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"However,","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"the image resolution is far too low for me to read.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"It appears to be a completely zoomed-out view where the code has been reduced to tiny, illegible pixels. Because of this, I cannot extract any text or logic to analyze.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"How You Can Share the Code","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"How You Can Share the Code","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"To help me review your code effectively, please try one of the following:","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Paste the text directly:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Copy the specific code blocks (both the old and new versions if possible) and paste them directly into our chat.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Upload the files:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"If the changes are extensive, you can upload the raw text or code files.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Take high-resolution screenshots:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"If you must use images, take closer, readable screenshots of the specific functions or methods you want me to review.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Once you provide the readable code, I can dive right in to identify potential bugs, assess performance bottlenecks, and help you summarize the changes for your PR!","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Good response","depth":22,"on_screen":false,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Bad response","depth":22,"on_screen":false,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Share & export","depth":21,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy","depth":22,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Show more options","depth":21,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy prompt","depth":21,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Edit","depth":21,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"You said app/Component/ES/Listeners/UpdateMultipleTargetsListener.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\\Component\\ES\\Listeners; namespace Jiminny\\Component\\ES\\Listeners; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Contracts\\ES\\Events\\UpdateMultipleEntities; use Jiminny\\Contracts\\ES\\Events\\UpdateMultipleEntities; use Psr\\Log\\LoggerInterface; use Psr\\Log\\LoggerInterface; AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntities(), $event->getEntities(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } } } app/Component/ES/Listeners/UpdateSingleTargetListener.php +9-1Lines changed: 9 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Actions\\TrackElasticSearchOperations; use Jiminny\\Component\\ES\\Actions\\TrackElasticSearchOperations; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder; use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Contracts\\ES\\Events\\UpdateSingleEntity; use Jiminny\\Contracts\\ES\\Events\\UpdateSingleEntity; use Psr\\Log\\LoggerInterface; use Psr\\Log\\LoggerInterface; 'entityId' => $event->getEntityId(), 'entityId' => $event->getEntityId(), ]); ]); /** * @important: * Synchronous event should eventually be deprecated. * Instant write operations are blocking and should be used sparingly. * It is much better in terms of performance to write 100 or 1000 documents at once, * and have one blocking reindex operation, instead of writing 10 documents synchronously. */ if ($event->isSyncEvent()) { if ($event->isSyncEvent()) { $this->handleSyncEvent($event); $this->handleSyncEvent($event); AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntityId(), $event->getEntityId(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } app/Component/ES/Processor/Actions/UpsertDocumentsAction.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Processor\\DTOs\\SimpleCollection; use Jiminny\\Component\\ES\\Processor\\DTOs\\SimpleCollection; use Jiminny\\Component\\ES\\Processor\\ResponseEvaluator; use Jiminny\\Component\\ES\\Processor\\ResponseEvaluator; use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait; use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Exceptions\\InvalidDataException; use Jiminny\\Exceptions\\InvalidDataException; use Sentry\\Laravel\\Facade as Sentry; use Sentry\\Laravel\\Facade as Sentry; AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( entityType: $this->updateTarget, entityType: $this->updateTarget, entityId: (int) $document->getId(), entityId: (int) $document->getId(), withPriority: true priority: QueuePriorityEnum::HIGH, ); ); } } app/Component/ES/Processor/DTOs/SelectionList.php +54-17Lines changed: 54 additions & 17 deletions Original file line numberOriginal file lineDiff line numberDiff line change namespace Jiminny\\Component\\ES\\Processor\\DTOs; namespace Jiminny\\Component\\ES\\Processor\\DTOs; use Jiminny\\Component\\ES\\QueuePriorityEnum; /** /** * A very basic and simple collection of entity IDs. * A very basic and simple collection of entity IDs. */ */ class SelectionList class SelectionList { { public function __construct( private const int DEFAULT_CHUNK = 200; private readonly array $priorityEntityIdList = [], private readonly array $normalEntityIdList = [], private int $chunkSize = self::DEFAULT_CHUNK; private readonly bool $isStaleChunkSelected = false, private bool $isStaleChunkSelected = false; private readonly int $chunkSize = 200, private array $selectedEntityIds = []; ) { // Do nothing public function setChunkSize(int $chunkSize): void { $this->chunkSize = $chunkSize; } } public function getAllIds(): array public function markStale(): void { { return array_merge($this->priorityEntityIdList, $this->normalEntityIdList); $this->isStaleChunkSelected = true; } } public function count(): int public function addEntityList(string|QueuePriorityEnum $priority, array $entityIds): void { { return count($this->priorityEntityIdList) + count($this->normalEntityIdList); $priorityKey = $this->normalisePriority($priority); if (! array_key_exists($priorityKey, $this->selectedEntityIds)) { $this->selectedEntityIds[$priorityKey] = []; } $this->selectedEntityIds[$priorityKey] = array_merge($this->selectedEntityIds[$priorityKey], $entityIds); } } public function isEmpty(): bool /** * @return string[] */ public function getEntityListGroups(): array { { return empty($this->priorityEntityIdList) && empty($this->normalEntityIdList); return array_keys($this->selectedEntityIds); } } public function getHighPriorityEntityIds(): array public function getEntityListItemsByGroup(string|QueuePriorityEnum $priority): array { { return $this->priorityEntityIdList; $priorityKey = $this->normalisePriority($priority); return $this->selectedEntityIds[$priorityKey] ?? []; } } public function getNormalPriorityEntityId(): array public function getAllIds(): array { { return $this->normalEntityIdList; $allIds = []; foreach ($this->selectedEntityIds as $entityIds) { $allIds = array_merge($allIds, $entityIds); } return $allIds; } public function count(): int { return array_sum( array_map('count', $this->selectedEntityIds) ); } public function isEmpty(): bool { return $this->count() === 0; } } public function isStaleChunkSelected(): bool public function isStaleChunkSelected(): bool { { return $this->count() >= $this->chunkSize; return $this->count() >= $this->chunkSize; } } private function normalisePriority(string|QueuePriorityEnum $priority): string { return $priority instanceof QueuePriorityEnum ? $priority->value : $priority; } } } app/Component/ES/Processor/Traits/SelectEntityListTrait.php +27-4Lines changed: 27 additions & 4 deletions Original file line numberOriginal file lineDiff line numberDiff line change use Illuminate\\Support\\Facades\\Log; use Illuminate\\Support\\Facades\\Log; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Exceptions\\InvalidArgumentException; use Jiminny\\Exceptions\\InvalidArgumentException; /** /** * Build the correct source list name for the type of entity and priority * Build the correct source list name for the type of entity and priority */ */ trait SelectEntityListTrait trait SelectEntityListTrait { { /** * Highest priority queue for data requiring near-instant availability. * Very few entities should be added here, only when absolutely necessary. */ private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; /** * Normal priority queue for normal application operations. * Almost all update events should pass through this queue */ private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; protected static function selectTargetList(string $entityType, bool $withPriority = false): string /** { * Nonblocking low priority queue. This queue will be consumed only when there is nothing * with higher priority. * * This queue will be used for operations such as es:reset-async */ private const string ENTITIES_LOW_PRIORITIES_LIST = '%s-for-update-low'; protected static function selectTargetList( string $entityType, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { if (! in_array($entityType, UpdateTarget::allowedTargets())) { if (! in_array($entityType, UpdateTarget::allowedTargets())) { throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); } } if ($withPriority) { if ($priority->isHigh()) { Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); } } if ($priority->isLow()) { return sprintf(self::ENTITIES_LOW_PRIORITIES_LIST, $entityType); } return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); } } } } app/Component/ES/Processor/TargetEntitiesSelector.php +26-21Lines changed: 26 additions & 21 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Processor\\DTOs\\SelectionList; use Jiminny\\Component\\ES\\Processor\\DTOs\\SelectionList; use Jiminny\\Component\\ES\\Processor\\Traits\\ExtractIdsTrait; use Jiminny\\Component\\ES\\Processor\\Traits\\ExtractIdsTrait; use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait; use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait; use Jiminny\\Component\\ES\\QueuePriorityEnum; /** /** * This class supplies a list of entities pending an update. * This class supplies a list of entities pending an update. public function select(): SelectionList public function select(): SelectionList { { $staleWorkEntityIds = $this->getStaleChunk(); $selectionList = new SelectionList(); $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $staleWorkEntityIds = $this->getStaleChunk(); if (count($staleWorkEntityIds) > 0) { if (count($staleWorkEntityIds) > 0) { return new SelectionList( /** priorityEntityIdList: $staleWorkEntityIds, * Stale chunks are treated as high priority isStaleChunkSelected: true, */ chunkSize: ChunkSize::getStaleChunkSize($this->updateTarget), $selectionList->markStale(); ); $selectionList->addEntityList(QueuePriorityEnum::HIGH, $staleWorkEntityIds); $selectionList->setChunkSize(ChunkSize::getStaleChunkSize($this->updateTarget)); return $selectionList; } } $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $selectionList->setChunkSize($mainChunkSize); $priorityEntityIdsList = $this->extractIdsFromSet( $priorityEntityIdsList = $this->extractIds(QueuePriorityEnum::HIGH, $mainChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, true), $selectionList->addEntityList(QueuePriorityEnum::HIGH, $priorityEntityIdsList); $mainChunkSize, ); $normalEntityIdsList = []; $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); if ($normalEntityChunkSize > 0) { if ($normalEntityChunkSize > 0) { $normalEntityIdsList = $this->extractIdsFromSet( $normalEntityIdsList = $this->extractIds(QueuePriorityEnum::NORMAL, $normalEntityChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, false), $selectionList->addEntityList(QueuePriorityEnum::NORMAL, $normalEntityIdsList); $normalEntityChunkSize ); } } return new SelectionList( return $selectionList; priorityEntityIdList: $priorityEntityIdsList, normalEntityIdList: $normalEntityIdsList, chunkSize: $mainChunkSize ); } } private function getStaleChunk(): array private function getStaleChunk(): array return []; return []; } } private function extractIds(QueuePriorityEnum $priority, int $chunkSize): array { return $this->extractIdsFromSet( AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, $priority), $chunkSize ); } } } app/Component/ES/AsyncUpdateElasticSearch.php +17-10Lines changed: 17 additions & 10 deletions Original file line numberOriginal file lineDiff line numberDiff line change * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * and other activity related data * and other activity related data */ */ public static function markEntityForUpdate(string $entityType, int $entityId, bool $withPriority = false): void public static function markEntityForUpdate( { string $entityType, $targetList = self::selectTargetList($entityType, $withPriority); int $entityId, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { $targetList = self::selectTargetList($entityType, $priority); Redis::sadd($targetList, $entityId); Redis::sadd($targetList, $entityId); Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ 'entityType' => $entityType, 'entityType' => $entityType, 'entityId' => $entityId, 'entityId' => $entityId, 'collectionKey' => $targetList, 'collectionKey' => $targetList, 'withPriority' => $withPriority, 'priority' => $priority->value, ]); ]); } } public static function bulkMarkEntitiesForUpdate( public static function bulkMarkEntitiesForUpdate( string $entityType, string $entityType, array $entityIds, array $entityIds, bool $withPriority = false QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { ): void { if (empty($entityIds)) { if (empty($entityIds)) { return; return; } } $targetList = self::selectTargetList($entityType, $withPriority); $targetList = self::selectTargetList($entityType, $priority); Redis::saddarray($targetList, $entityIds); Redis::saddarray($targetList, $entityIds); } } * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Takes priority into consideration. * Takes priority into consideration. */ */ public static function getEntitiesSourceList(string $updateTarget, $priority = false): string public static function getEntitiesSourceList( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { return self::selectTargetList($updateTarget, $priority); return self::selectTargetList($updateTarget, $priority); } } /** /** * Externally called helper methods * Externally called helper methods * - count and flush * - count and flush */ */ public static function getEntitiesListCount(string $updateTarget, $priority = false): int public static function getEntitiesListCount( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): int { $targetList = self::selectTargetList($updateTarget, $priority); $targetList = self::selectTargetList($updateTarget, $priority); return Redis::scard($targetList); return Redis::scard($targetList); app/Component/ES/QueuePriorityEnum.php +40Lines changed: 40 additions & 0 deletions Original file line numberOriginal file lineDiff line numberDiff line change <?php declare(strict_types=1); namespace Jiminny\\Component\\ES; use Jiminny\\Exceptions\\InvalidArgumentException; enum QueuePriorityEnum: string { case HIGH = 'high'; case NORMAL = 'normal'; case LOW = 'low'; public static function tryFromString(string $value): self { if (! self::isValid($value)) { throw new InvalidArgumentException( sprintf('Invalid queue priority \"%s\" selected', $value) ); } return self::tryFrom($value); } public static function isValid(string $value): bool { return self::tryFrom($value) !== null; } public function isLow(): bool { return $this === self::LOW; } public function isHigh(): bool { return $this === self::HIGH; } } app/Component/ES/UpdateProcessManager.php +12-9Lines changed: 12 additions & 9 deletions Original file line numberOriginal file lineDiff line numberDiff line change if ($selectionList->isEmpty()) { if ($selectionList->isEmpty()) { return false; return false; } } /** /** * A stale chunk will always be smaller than a regular chunk. * A stale chunk will always be smaller than a regular chunk. * That doesn't mean there aren't any other scheduled entities for processing * That doesn't mean there aren't any other scheduled entities for processing private function rescheduleThrottledEntities(SelectionList $selectionList): void private function rescheduleThrottledEntities(SelectionList $selectionList): void { { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $groups = $selectionList->getEntityListGroups(); $this->updateTarget, foreach ($groups as $eachGroup) { $selectionList->getNormalPriorityEntityId() $groupEntityIds = $selectionList->getEntityListItemsByGroup($eachGroup); ); if (! empty($groupEntityIds)) { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $this->updateTarget, entityType: $this->updateTarget, $selectionList->getHighPriorityEntityIds(), entityIds: $groupEntityIds, true priority: QueuePriorityEnum::tryFromString($eachGroup) ); ); } } } } } } app/Console/Commands/Elasticsearch/AsyncUpdateEsEntities.php +9-3Lines changed: 9 additions & 3 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Illuminate\\Support\\Str; use Illuminate\\Support\\Str; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Component\\ES\\UpdateProcessManager; use Jiminny\\Component\\ES\\UpdateProcessManager; use Jiminny\\Exceptions\\InvalidArgumentException; use Jiminny\\Exceptions\\InvalidArgumentException; use Jiminny\\Traits\\GracefullyStoppable; use Jiminny\\Traits\\GracefullyStoppable; Redis::set($gaugeLockName, true); Redis::set($gaugeLockName, true); Redis::expire($gaugeLockName, 60); Redis::expire($gaugeLockName, 60); $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::HIGH), ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update', $updateTarget), stat: sprintf('jiminny.%s-for-update', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::NORMAL), ); ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), stat: sprintf('jiminny.%s-for-update-low', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, true), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::LOW), ); ); } } app/Console/Commands/Elasticsearch/ResetAsyncElasticSearchCommand.php +5-1Lines changed: 5 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder; use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder; use Jiminny\\Component\\ES\\Processor\\Traits\\ValidateUpdateTargetTrait; use Jiminny\\Component\\ES\\Processor\\Traits\\ValidateUpdateTargetTrait; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Component\\ES\\Repositories\\EsResetRepositoryInterface; use Jiminny\\Component\\ES\\Repositories\\EsResetRepositoryInterface; use Jiminny\\Exceptions\\InvalidArgumentException; use Jiminny\\Exceptions\\InvalidArgumentException; use Jiminny\\Traits\\GracefullyStoppable; use Jiminny\\Traits\\GracefullyStoppable; private function getRemainingScheduledEntities(bool $printStatus = false): int private function getRemainingScheduledEntities(bool $printStatus = false): int { { $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget, true); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount( $this->updateTarget, QueuePriorityEnum::HIGH ); if ($printStatus) { if ($printStatus) { $this->line( $this->line(","depth":21,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"You said","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app/Component/ES/Listeners/UpdateMultipleTargetsListener.php","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"+2-1Lines changed: 2 additions & 1 deletion","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\\Component\\ES\\Listeners;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"namespace Jiminny\\Component\\ES\\Listeners;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\QueuePriorityEnum;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Contracts\\ES\\Events\\UpdateMultipleEntities;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Contracts\\ES\\Events\\UpdateMultipleEntities;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Psr\\Log\\LoggerInterface;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Psr\\Log\\LoggerInterface;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getUpdateTargetValue(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getUpdateTargetValue(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getEntities(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getEntities(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->isPriority()","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL,","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":");","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":");","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app/Component/ES/Listeners/UpdateSingleTargetListener.php","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"+9-1Lines changed: 9 additions & 1 deletion","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Actions\\TrackElasticSearchOperations;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Actions\\TrackElasticSearchOperations;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\QueuePriorityEnum;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Contracts\\ES\\Events\\UpdateSingleEntity;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Contracts\\ES\\Events\\UpdateSingleEntity;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Psr\\Log\\LoggerInterface;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Psr\\Log\\LoggerInterface;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"'entityId' => $event->getEntityId(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"'entityId' => $event->getEntityId(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"]);","depth":23,"bounds":{"left":0.20578457,"top":0.0,"width":0.0051529254,"height":0.016360734},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"]);","depth":23,"bounds":{"left":0.20578457,"top":0.0,"width":0.0051529254,"height":0.016360734},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/**","depth":23,"bounds":{"left":0.20578457,"top":0.024740623,"width":0.0066489363,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* @important:","depth":23,"bounds":{"left":0.20578457,"top":0.08220271,"width":0.03374335,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* Synchronous event should eventually be deprecated.","depth":23,"bounds":{"left":0.20578457,"top":0.1396648,"width":0.13131648,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* Instant write operations are blocking and should be used sparingly.","depth":23,"bounds":{"left":0.20578457,"top":0.1971269,"width":0.12732713,"height":0.035514764},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* It is much better in terms of performance to write 100 or 1000 documents at once,","depth":23,"bounds":{"left":0.20578457,"top":0.273743,"width":0.13314494,"height":0.035514764},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* and have one blocking reindex operation, instead of writing 10 documents synchronously.","depth":23,"bounds":{"left":0.20578457,"top":0.35035914,"width":0.12865691,"height":0.035514764},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"*/","depth":23,"bounds":{"left":0.20578457,"top":0.42697525,"width":0.004155585,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"if ($event->isSyncEvent()) {","depth":23,"bounds":{"left":0.20578457,"top":0.4461293,"width":0.065990694,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"if ($event->isSyncEvent()) {","depth":23,"bounds":{"left":0.20578457,"top":0.46528333,"width":0.065990694,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$this->handleSyncEvent($event);","depth":23,"bounds":{"left":0.20578457,"top":0.48443735,"width":0.08028591,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$this->handleSyncEvent($event);","depth":23,"bounds":{"left":0.20578457,"top":0.50359136,"width":0.08028591,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AsyncUpdateElasticSearch::markEntityForUpdate(","depth":23,"bounds":{"left":0.20578457,"top":0.56105345,"width":0.12117686,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AsyncUpdateElasticSearch::markEntityForUpdate(","depth":23,"bounds":{"left":0.20578457,"top":0.5802075,"width":0.12117686,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getUpdateTargetValue(),","depth":23,"bounds":{"left":0.20578457,"top":0.59936154,"width":0.0809508,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getUpdateTargetValue(),","depth":23,"bounds":{"left":0.20578457,"top":0.61851555,"width":0.0809508,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getEntityId(),","depth":23,"bounds":{"left":0.20578457,"top":0.63766956,"width":0.053025264,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getEntityId(),","depth":23,"bounds":{"left":0.20578457,"top":0.65682364,"width":0.053025264,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->isPriority()","depth":23,"bounds":{"left":0.20578457,"top":0.67597765,"width":0.046708778,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL,","depth":23,"bounds":{"left":0.20578457,"top":0.69513166,"width":0.11702128,"height":0.035514764},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":");","depth":23,"bounds":{"left":0.20578457,"top":0.73343974,"width":0.0033244682,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":");","depth":23,"bounds":{"left":0.20578457,"top":0.75259376,"width":0.0033244682,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"bounds":{"left":0.20578457,"top":0.7717478,"width":0.0019946808,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"bounds":{"left":0.20578457,"top":0.79090184,"width":0.0019946808,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app/Component/ES/Processor/Actions/UpsertDocumentsAction.php","depth":23,"bounds":{"left":0.20578457,"top":0.84836394,"width":0.09375,"height":0.035514764},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"+2-1Lines changed: 2 additions & 1 deletion","depth":23,"bounds":{"left":0.20578457,"top":0.90582603,"width":0.10388963,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Processor\\DTOs\\SimpleCollection;","depth":23,"bounds":{"left":0.20578457,"top":0.94413406,"width":0.1356383,"height":0.055865943},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\DTOs\\SimpleCollection;","depth":23,"bounds":{"left":0.20578457,"top":1.0,"width":0.1356383,"height":-0.020750165},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\ResponseEvaluator;","depth":23,"bounds":{"left":0.20578457,"top":1.0,"width":0.13115026,"height":-0.07821226},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\ResponseEvaluator;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\QueuePriorityEnum;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Exceptions\\InvalidDataException;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Exceptions\\InvalidDataException;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Sentry\\Laravel\\Facade as Sentry;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Sentry\\Laravel\\Facade as Sentry;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AsyncUpdateElasticSearch::markEntityForUpdate(","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AsyncUpdateElasticSearch::markEntityForUpdate(","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"entityType: $this->updateTarget,","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"entityType: $this->updateTarget,","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"entityId: (int) $document->getId(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"entityId: (int) $document->getId(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"withPriority: true","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"priority: QueuePriorityEnum::HIGH,","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":");","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":");","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app/Component/ES/Processor/DTOs/SelectionList.php","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"+54-17Lines changed: 54 additions & 17 deletions","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Original file line numberOriginal file lineDiff line numberDiff line change","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"namespace Jiminny\\Component\\ES\\Processor\\DTOs;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"namespace Jiminny\\Component\\ES\\Processor\\DTOs;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\QueuePriorityEnum;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/**","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/**","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* A very basic and simple collection of entity IDs.","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* A very basic and simple collection of entity IDs.","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"*/","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"*/","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"class SelectionList","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"class SelectionList","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function __construct(","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private const int DEFAULT_CHUNK = 200;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private readonly array $priorityEntityIdList = [],","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private readonly array $normalEntityIdList = [],","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private int $chunkSize = self::DEFAULT_CHUNK;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private readonly bool $isStaleChunkSelected = false,","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private bool $isStaleChunkSelected = false;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private readonly int $chunkSize = 200,","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private array $selectedEntityIds = [];","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":") {","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"// Do nothing","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function setChunkSize(int $chunkSize): void","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$this->chunkSize = $chunkSize;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function getAllIds(): array","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function markStale(): void","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"return array_merge($this->priorityEntityIdList, $this->normalEntityIdList);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$this->isStaleChunkSelected = true;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function count(): int","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function addEntityList(string|QueuePriorityEnum $priority, array $entityIds): void","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"return count($this->priorityEntityIdList) + count($this->normalEntityIdList);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$priorityKey = $this->normalisePriority($priority);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"if (! array_key_exists($priorityKey, $this->selectedEntityIds)) {","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$this->selectedEntityIds[$priorityKey] = [];","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$this->selectedEntityIds[$priorityKey] = array_merge($this->selectedEntityIds[$priorityKey], $entityIds);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function isEmpty(): bool","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/**","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* @return string[]","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"*/","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function getEntityListGroups(): array","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"return empty($this->priorityEntityIdList) && empty($this->normalEntityIdList);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"return array_keys($this->selectedEntityIds);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function getHighPriorityEntityIds(): array","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function getEntityListItemsByGroup(string|QueuePriorityEnum $priority): array","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"return $this->priorityEntityIdList;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$priorityKey = $this->normalisePriority($priority);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"return $this->selectedEntityIds[$priorityKey] ?? [];","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function getNormalPriorityEntityId(): array","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function getAllIds(): array","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"return $this->normalEntityIdList;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$allIds = [];","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"foreach ($this->selectedEntityIds as $entityIds) {","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$allIds = array_merge($allIds, $entityIds);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"return $allIds;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function count(): int","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"return array_sum(","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"array_map('count', $this->selectedEntityIds)","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":");","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function isEmpty(): bool","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"return $this->count() === 0;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function isStaleChunkSelected(): bool","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function isStaleChunkSelected(): bool","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"return $this->count() >= $this->chunkSize;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"return $this->count() >= $this->chunkSize;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private function normalisePriority(string|QueuePriorityEnum $priority): string","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"return $priority instanceof QueuePriorityEnum ? $priority->value : $priority;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app/Component/ES/Processor/Traits/SelectEntityListTrait.php","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"+27-4Lines changed: 27 additions & 4 deletions","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Original file line numberOriginal file lineDiff line numberDiff line change","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Illuminate\\Support\\Facades\\Log;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Illuminate\\Support\\Facades\\Log;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\UpdateTarget;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\UpdateTarget;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\QueuePriorityEnum;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Exceptions\\InvalidArgumentException;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Exceptions\\InvalidArgumentException;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/**","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/**","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* Build the correct source list name for the type of entity and priority","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* Build the correct source list name for the type of entity and priority","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"*/","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"*/","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"trait SelectEntityListTrait","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"trait SelectEntityListTrait","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/**","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* Highest priority queue for data requiring near-instant availability.","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* Very few entities should be added here, only when absolutely necessary.","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"*/","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority';","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/**","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* Normal priority queue for normal application operations.","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* Almost all update events should pass through this queue","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"*/","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update';","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update';","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority';","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"protected static function selectTargetList(string $entityType, bool $withPriority = false): string","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/**","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* Nonblocking low priority queue. This queue will be consumed only when there is nothing","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"}]...
|
-6808289842967995685
|
-1145577539136185202
|
visual_change
|
accessibility
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
Close tab
New Tab
Customize sidebar
Close Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
AI Chat settings
Close
WORK, Google Account: [EMAIL]
Main menu
New chat
Gemini
New Chat
Open menu for conversation actions.
Conversation with Gemini
Conversation with Gemini
Show the uploaded image in a lightbox
Copy prompt
You said Make a PR of changes Find potential issues and bottlenecks
You said
Make a PR of changes Find potential issues and bottlenecks
Listen
Show thinking
Gemini said
Gemini said
I can see you've uploaded a screenshot of a code diff, likely from a version control system given the red and green highlights. I would love to help you review the changes, spot bottlenecks, and help you draft a Pull Request.
However,
the image resolution is far too low for me to read.
It appears to be a completely zoomed-out view where the code has been reduced to tiny, illegible pixels. Because of this, I cannot extract any text or logic to analyze.
How You Can Share the Code
How You Can Share the Code
To help me review your code effectively, please try one of the following:
Paste the text directly:
Copy the specific code blocks (both the old and new versions if possible) and paste them directly into our chat.
Upload the files:
If the changes are extensive, you can upload the raw text or code files.
Take high-resolution screenshots:
If you must use images, take closer, readable screenshots of the specific functions or methods you want me to review.
Once you provide the readable code, I can dive right in to identify potential bugs, assess performance bottlenecks, and help you summarize the changes for your PR!
Good response
Bad response
Share & export
Copy
Show more options
Copy prompt
Edit
You said app/Component/ES/Listeners/UpdateMultipleTargetsListener.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\Component\ES\Listeners; namespace Jiminny\Component\ES\Listeners; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Contracts\ES\Events\UpdateMultipleEntities; use Jiminny\Contracts\ES\Events\UpdateMultipleEntities; use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface; AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntities(), $event->getEntities(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } } } app/Component/ES/Listeners/UpdateSingleTargetListener.php +9-1Lines changed: 9 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Actions\TrackElasticSearchOperations; use Jiminny\Component\ES\Actions\TrackElasticSearchOperations; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Contracts\ES\Events\UpdateSingleEntity; use Jiminny\Contracts\ES\Events\UpdateSingleEntity; use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface; 'entityId' => $event->getEntityId(), 'entityId' => $event->getEntityId(), ]); ]); /** * @important: * Synchronous event should eventually be deprecated. * Instant write operations are blocking and should be used sparingly. * It is much better in terms of performance to write 100 or 1000 documents at once, * and have one blocking reindex operation, instead of writing 10 documents synchronously. */ if ($event->isSyncEvent()) { if ($event->isSyncEvent()) { $this->handleSyncEvent($event); $this->handleSyncEvent($event); AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntityId(), $event->getEntityId(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } app/Component/ES/Processor/Actions/UpsertDocumentsAction.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SimpleCollection; use Jiminny\Component\ES\Processor\DTOs\SimpleCollection; use Jiminny\Component\ES\Processor\ResponseEvaluator; use Jiminny\Component\ES\Processor\ResponseEvaluator; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Exceptions\InvalidDataException; use Jiminny\Exceptions\InvalidDataException; use Sentry\Laravel\Facade as Sentry; use Sentry\Laravel\Facade as Sentry; AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( entityType: $this->updateTarget, entityType: $this->updateTarget, entityId: (int) $document->getId(), entityId: (int) $document->getId(), withPriority: true priority: QueuePriorityEnum::HIGH, ); ); } } app/Component/ES/Processor/DTOs/SelectionList.php +54-17Lines changed: 54 additions & 17 deletions Original file line numberOriginal file lineDiff line numberDiff line change namespace Jiminny\Component\ES\Processor\DTOs; namespace Jiminny\Component\ES\Processor\DTOs; use Jiminny\Component\ES\QueuePriorityEnum; /** /** * A very basic and simple collection of entity IDs. * A very basic and simple collection of entity IDs. */ */ class SelectionList class SelectionList { { public function __construct( private const int DEFAULT_CHUNK = 200; private readonly array $priorityEntityIdList = [], private readonly array $normalEntityIdList = [], private int $chunkSize = self::DEFAULT_CHUNK; private readonly bool $isStaleChunkSelected = false, private bool $isStaleChunkSelected = false; private readonly int $chunkSize = 200, private array $selectedEntityIds = []; ) { // Do nothing public function setChunkSize(int $chunkSize): void { $this->chunkSize = $chunkSize; } } public function getAllIds(): array public function markStale(): void { { return array_merge($this->priorityEntityIdList, $this->normalEntityIdList); $this->isStaleChunkSelected = true; } } public function count(): int public function addEntityList(string|QueuePriorityEnum $priority, array $entityIds): void { { return count($this->priorityEntityIdList) + count($this->normalEntityIdList); $priorityKey = $this->normalisePriority($priority); if (! array_key_exists($priorityKey, $this->selectedEntityIds)) { $this->selectedEntityIds[$priorityKey] = []; } $this->selectedEntityIds[$priorityKey] = array_merge($this->selectedEntityIds[$priorityKey], $entityIds); } } public function isEmpty(): bool /** * @return string[] */ public function getEntityListGroups(): array { { return empty($this->priorityEntityIdList) && empty($this->normalEntityIdList); return array_keys($this->selectedEntityIds); } } public function getHighPriorityEntityIds(): array public function getEntityListItemsByGroup(string|QueuePriorityEnum $priority): array { { return $this->priorityEntityIdList; $priorityKey = $this->normalisePriority($priority); return $this->selectedEntityIds[$priorityKey] ?? []; } } public function getNormalPriorityEntityId(): array public function getAllIds(): array { { return $this->normalEntityIdList; $allIds = []; foreach ($this->selectedEntityIds as $entityIds) { $allIds = array_merge($allIds, $entityIds); } return $allIds; } public function count(): int { return array_sum( array_map('count', $this->selectedEntityIds) ); } public function isEmpty(): bool { return $this->count() === 0; } } public function isStaleChunkSelected(): bool public function isStaleChunkSelected(): bool { { return $this->count() >= $this->chunkSize; return $this->count() >= $this->chunkSize; } } private function normalisePriority(string|QueuePriorityEnum $priority): string { return $priority instanceof QueuePriorityEnum ? $priority->value : $priority; } } } app/Component/ES/Processor/Traits/SelectEntityListTrait.php +27-4Lines changed: 27 additions & 4 deletions Original file line numberOriginal file lineDiff line numberDiff line change use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; /** /** * Build the correct source list name for the type of entity and priority * Build the correct source list name for the type of entity and priority */ */ trait SelectEntityListTrait trait SelectEntityListTrait { { /** * Highest priority queue for data requiring near-instant availability. * Very few entities should be added here, only when absolutely necessary. */ private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; /** * Normal priority queue for normal application operations. * Almost all update events should pass through this queue */ private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; protected static function selectTargetList(string $entityType, bool $withPriority = false): string /** { * Nonblocking low priority queue. This queue will be consumed only when there is nothing * with higher priority. * * This queue will be used for operations such as es:reset-async */ private const string ENTITIES_LOW_PRIORITIES_LIST = '%s-for-update-low'; protected static function selectTargetList( string $entityType, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { if (! in_array($entityType, UpdateTarget::allowedTargets())) { if (! in_array($entityType, UpdateTarget::allowedTargets())) { throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); } } if ($withPriority) { if ($priority->isHigh()) { Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); } } if ($priority->isLow()) { return sprintf(self::ENTITIES_LOW_PRIORITIES_LIST, $entityType); } return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); } } } } app/Component/ES/Processor/TargetEntitiesSelector.php +26-21Lines changed: 26 additions & 21 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SelectionList; use Jiminny\Component\ES\Processor\DTOs\SelectionList; use Jiminny\Component\ES\Processor\Traits\ExtractIdsTrait; use Jiminny\Component\ES\Processor\Traits\ExtractIdsTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\QueuePriorityEnum; /** /** * This class supplies a list of entities pending an update. * This class supplies a list of entities pending an update. public function select(): SelectionList public function select(): SelectionList { { $staleWorkEntityIds = $this->getStaleChunk(); $selectionList = new SelectionList(); $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $staleWorkEntityIds = $this->getStaleChunk(); if (count($staleWorkEntityIds) > 0) { if (count($staleWorkEntityIds) > 0) { return new SelectionList( /** priorityEntityIdList: $staleWorkEntityIds, * Stale chunks are treated as high priority isStaleChunkSelected: true, */ chunkSize: ChunkSize::getStaleChunkSize($this->updateTarget), $selectionList->markStale(); ); $selectionList->addEntityList(QueuePriorityEnum::HIGH, $staleWorkEntityIds); $selectionList->setChunkSize(ChunkSize::getStaleChunkSize($this->updateTarget)); return $selectionList; } } $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $selectionList->setChunkSize($mainChunkSize); $priorityEntityIdsList = $this->extractIdsFromSet( $priorityEntityIdsList = $this->extractIds(QueuePriorityEnum::HIGH, $mainChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, true), $selectionList->addEntityList(QueuePriorityEnum::HIGH, $priorityEntityIdsList); $mainChunkSize, ); $normalEntityIdsList = []; $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); if ($normalEntityChunkSize > 0) { if ($normalEntityChunkSize > 0) { $normalEntityIdsList = $this->extractIdsFromSet( $normalEntityIdsList = $this->extractIds(QueuePriorityEnum::NORMAL, $normalEntityChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, false), $selectionList->addEntityList(QueuePriorityEnum::NORMAL, $normalEntityIdsList); $normalEntityChunkSize ); } } return new SelectionList( return $selectionList; priorityEntityIdList: $priorityEntityIdsList, normalEntityIdList: $normalEntityIdsList, chunkSize: $mainChunkSize ); } } private function getStaleChunk(): array private function getStaleChunk(): array return []; return []; } } private function extractIds(QueuePriorityEnum $priority, int $chunkSize): array { return $this->extractIdsFromSet( AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, $priority), $chunkSize ); } } } app/Component/ES/AsyncUpdateElasticSearch.php +17-10Lines changed: 17 additions & 10 deletions Original file line numberOriginal file lineDiff line numberDiff line change * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * and other activity related data * and other activity related data */ */ public static function markEntityForUpdate(string $entityType, int $entityId, bool $withPriority = false): void public static function markEntityForUpdate( { string $entityType, $targetList = self::selectTargetList($entityType, $withPriority); int $entityId, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { $targetList = self::selectTargetList($entityType, $priority); Redis::sadd($targetList, $entityId); Redis::sadd($targetList, $entityId); Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ 'entityType' => $entityType, 'entityType' => $entityType, 'entityId' => $entityId, 'entityId' => $entityId, 'collectionKey' => $targetList, 'collectionKey' => $targetList, 'withPriority' => $withPriority, 'priority' => $priority->value, ]); ]); } } public static function bulkMarkEntitiesForUpdate( public static function bulkMarkEntitiesForUpdate( string $entityType, string $entityType, array $entityIds, array $entityIds, bool $withPriority = false QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { ): void { if (empty($entityIds)) { if (empty($entityIds)) { return; return; } } $targetList = self::selectTargetList($entityType, $withPriority); $targetList = self::selectTargetList($entityType, $priority); Redis::saddarray($targetList, $entityIds); Redis::saddarray($targetList, $entityIds); } } * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Takes priority into consideration. * Takes priority into consideration. */ */ public static function getEntitiesSourceList(string $updateTarget, $priority = false): string public static function getEntitiesSourceList( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { return self::selectTargetList($updateTarget, $priority); return self::selectTargetList($updateTarget, $priority); } } /** /** * Externally called helper methods * Externally called helper methods * - count and flush * - count and flush */ */ public static function getEntitiesListCount(string $updateTarget, $priority = false): int public static function getEntitiesListCount( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): int { $targetList = self::selectTargetList($updateTarget, $priority); $targetList = self::selectTargetList($updateTarget, $priority); return Redis::scard($targetList); return Redis::scard($targetList); app/Component/ES/QueuePriorityEnum.php +40Lines changed: 40 additions & 0 deletions Original file line numberOriginal file lineDiff line numberDiff line change <?php declare(strict_types=1); namespace Jiminny\Component\ES; use Jiminny\Exceptions\InvalidArgumentException; enum QueuePriorityEnum: string { case HIGH = 'high'; case NORMAL = 'normal'; case LOW = 'low'; public static function tryFromString(string $value): self { if (! self::isValid($value)) { throw new InvalidArgumentException( sprintf('Invalid queue priority "%s" selected', $value) ); } return self::tryFrom($value); } public static function isValid(string $value): bool { return self::tryFrom($value) !== null; } public function isLow(): bool { return $this === self::LOW; } public function isHigh(): bool { return $this === self::HIGH; } } app/Component/ES/UpdateProcessManager.php +12-9Lines changed: 12 additions & 9 deletions Original file line numberOriginal file lineDiff line numberDiff line change if ($selectionList->isEmpty()) { if ($selectionList->isEmpty()) { return false; return false; } } /** /** * A stale chunk will always be smaller than a regular chunk. * A stale chunk will always be smaller than a regular chunk. * That doesn't mean there aren't any other scheduled entities for processing * That doesn't mean there aren't any other scheduled entities for processing private function rescheduleThrottledEntities(SelectionList $selectionList): void private function rescheduleThrottledEntities(SelectionList $selectionList): void { { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $groups = $selectionList->getEntityListGroups(); $this->updateTarget, foreach ($groups as $eachGroup) { $selectionList->getNormalPriorityEntityId() $groupEntityIds = $selectionList->getEntityListItemsByGroup($eachGroup); ); if (! empty($groupEntityIds)) { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $this->updateTarget, entityType: $this->updateTarget, $selectionList->getHighPriorityEntityIds(), entityIds: $groupEntityIds, true priority: QueuePriorityEnum::tryFromString($eachGroup) ); ); } } } } } } app/Console/Commands/Elasticsearch/AsyncUpdateEsEntities.php +9-3Lines changed: 9 additions & 3 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Illuminate\Support\Str; use Illuminate\Support\Str; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Component\ES\UpdateProcessManager; use Jiminny\Component\ES\UpdateProcessManager; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Traits\GracefullyStoppable; use Jiminny\Traits\GracefullyStoppable; Redis::set($gaugeLockName, true); Redis::set($gaugeLockName, true); Redis::expire($gaugeLockName, 60); Redis::expire($gaugeLockName, 60); $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::HIGH), ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update', $updateTarget), stat: sprintf('jiminny.%s-for-update', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::NORMAL), ); ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), stat: sprintf('jiminny.%s-for-update-low', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, true), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::LOW), ); ); } } app/Console/Commands/Elasticsearch/ResetAsyncElasticSearchCommand.php +5-1Lines changed: 5 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\Traits\ValidateUpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\ValidateUpdateTargetTrait; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Component\ES\Repositories\EsResetRepositoryInterface; use Jiminny\Component\ES\Repositories\EsResetRepositoryInterface; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Traits\GracefullyStoppable; use Jiminny\Traits\GracefullyStoppable; private function getRemainingScheduledEntities(bool $printStatus = false): int private function getRemainingScheduledEntities(bool $printStatus = false): int { { $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget, true); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount( $this->updateTarget, QueuePriorityEnum::HIGH ); if ($printStatus) { if ($printStatus) { $this->line( $this->line(
You said
app/Component/ES/Listeners/UpdateMultipleTargetsListener.php
+2-1Lines changed: 2 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\Component\ES\Listeners;
namespace Jiminny\Component\ES\Listeners;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\QueuePriorityEnum;
use Jiminny\Contracts\ES\Events\UpdateMultipleEntities;
use Jiminny\Contracts\ES\Events\UpdateMultipleEntities;
use Psr\Log\LoggerInterface;
use Psr\Log\LoggerInterface;
AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(
AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(
$event->getUpdateTargetValue(),
$event->getUpdateTargetValue(),
$event->getEntities(),
$event->getEntities(),
$event->isPriority()
$event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL,
);
);
}
}
}
}
app/Component/ES/Listeners/UpdateSingleTargetListener.php
+9-1Lines changed: 9 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Actions\TrackElasticSearchOperations;
use Jiminny\Component\ES\Actions\TrackElasticSearchOperations;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\Processor\EntityQueryBuilder;
use Jiminny\Component\ES\Processor\EntityQueryBuilder;
use Jiminny\Component\ES\QueuePriorityEnum;
use Jiminny\Contracts\ES\Events\UpdateSingleEntity;
use Jiminny\Contracts\ES\Events\UpdateSingleEntity;
use Psr\Log\LoggerInterface;
use Psr\Log\LoggerInterface;
'entityId' => $event->getEntityId(),
'entityId' => $event->getEntityId(),
]);
]);
/**
* @important:
* Synchronous event should eventually be deprecated.
* Instant write operations are blocking and should be used sparingly.
* It is much better in terms of performance to write 100 or 1000 documents at once,
* and have one blocking reindex operation, instead of writing 10 documents synchronously.
*/
if ($event->isSyncEvent()) {
if ($event->isSyncEvent()) {
$this->handleSyncEvent($event);
$this->handleSyncEvent($event);
AsyncUpdateElasticSearch::markEntityForUpdate(
AsyncUpdateElasticSearch::markEntityForUpdate(
$event->getUpdateTargetValue(),
$event->getUpdateTargetValue(),
$event->getEntityId(),
$event->getEntityId(),
$event->isPriority()
$event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL,
);
);
}
}
app/Component/ES/Processor/Actions/UpsertDocumentsAction.php
+2-1Lines changed: 2 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SimpleCollection;
use Jiminny\Component\ES\Processor\DTOs\SimpleCollection;
use Jiminny\Component\ES\Processor\ResponseEvaluator;
use Jiminny\Component\ES\Processor\ResponseEvaluator;
use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait;
use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait;
use Jiminny\Component\ES\QueuePriorityEnum;
use Jiminny\Exceptions\InvalidDataException;
use Jiminny\Exceptions\InvalidDataException;
use Sentry\Laravel\Facade as Sentry;
use Sentry\Laravel\Facade as Sentry;
AsyncUpdateElasticSearch::markEntityForUpdate(
AsyncUpdateElasticSearch::markEntityForUpdate(
entityType: $this->updateTarget,
entityType: $this->updateTarget,
entityId: (int) $document->getId(),
entityId: (int) $document->getId(),
withPriority: true
priority: QueuePriorityEnum::HIGH,
);
);
}
}
app/Component/ES/Processor/DTOs/SelectionList.php
+54-17Lines changed: 54 additions & 17 deletions
Original file line numberOriginal file lineDiff line numberDiff line change
namespace Jiminny\Component\ES\Processor\DTOs;
namespace Jiminny\Component\ES\Processor\DTOs;
use Jiminny\Component\ES\QueuePriorityEnum;
/**
/**
* A very basic and simple collection of entity IDs.
* A very basic and simple collection of entity IDs.
*/
*/
class SelectionList
class SelectionList
{
{
public function __construct(
private const int DEFAULT_CHUNK = 200;
private readonly array $priorityEntityIdList = [],
private readonly array $normalEntityIdList = [],
private int $chunkSize = self::DEFAULT_CHUNK;
private readonly bool $isStaleChunkSelected = false,
private bool $isStaleChunkSelected = false;
private readonly int $chunkSize = 200,
private array $selectedEntityIds = [];
) {
// Do nothing
public function setChunkSize(int $chunkSize): void
{
$this->chunkSize = $chunkSize;
}
}
public function getAllIds(): array
public function markStale(): void
{
{
return array_merge($this->priorityEntityIdList, $this->normalEntityIdList);
$this->isStaleChunkSelected = true;
}
}
public function count(): int
public function addEntityList(string|QueuePriorityEnum $priority, array $entityIds): void
{
{
return count($this->priorityEntityIdList) + count($this->normalEntityIdList);
$priorityKey = $this->normalisePriority($priority);
if (! array_key_exists($priorityKey, $this->selectedEntityIds)) {
$this->selectedEntityIds[$priorityKey] = [];
}
$this->selectedEntityIds[$priorityKey] = array_merge($this->selectedEntityIds[$priorityKey], $entityIds);
}
}
public function isEmpty(): bool
/**
* @return string[]
*/
public function getEntityListGroups(): array
{
{
return empty($this->priorityEntityIdList) && empty($this->normalEntityIdList);
return array_keys($this->selectedEntityIds);
}
}
public function getHighPriorityEntityIds(): array
public function getEntityListItemsByGroup(string|QueuePriorityEnum $priority): array
{
{
return $this->priorityEntityIdList;
$priorityKey = $this->normalisePriority($priority);
return $this->selectedEntityIds[$priorityKey] ?? [];
}
}
public function getNormalPriorityEntityId(): array
public function getAllIds(): array
{
{
return $this->normalEntityIdList;
$allIds = [];
foreach ($this->selectedEntityIds as $entityIds) {
$allIds = array_merge($allIds, $entityIds);
}
return $allIds;
}
public function count(): int
{
return array_sum(
array_map('count', $this->selectedEntityIds)
);
}
public function isEmpty(): bool
{
return $this->count() === 0;
}
}
public function isStaleChunkSelected(): bool
public function isStaleChunkSelected(): bool
{
{
return $this->count() >= $this->chunkSize;
return $this->count() >= $this->chunkSize;
}
}
private function normalisePriority(string|QueuePriorityEnum $priority): string
{
return $priority instanceof QueuePriorityEnum ? $priority->value : $priority;
}
}
}
app/Component/ES/Processor/Traits/SelectEntityListTrait.php
+27-4Lines changed: 27 additions & 4 deletions
Original file line numberOriginal file lineDiff line numberDiff line change
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Log;
use Jiminny\Component\ES\Processor\UpdateTarget;
use Jiminny\Component\ES\Processor\UpdateTarget;
use Jiminny\Component\ES\QueuePriorityEnum;
use Jiminny\Exceptions\InvalidArgumentException;
use Jiminny\Exceptions\InvalidArgumentException;
/**
/**
* Build the correct source list name for the type of entity and priority
* Build the correct source list name for the type of entity and priority
*/
*/
trait SelectEntityListTrait
trait SelectEntityListTrait
{
{
/**
* Highest priority queue for data requiring near-instant availability.
* Very few entities should be added here, only when absolutely necessary.
*/
private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority';
/**
* Normal priority queue for normal application operations.
* Almost all update events should pass through this queue
*/
private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update';
private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update';
private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority';
protected static function selectTargetList(string $entityType, bool $withPriority = false): string
/**
{
* Nonblocking low priority queue. This queue will be consumed only when there is nothing...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
55702
|
1934
|
2
|
2026-05-19T06:43:00.315003+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779172980315_m1.jpg...
|
Firefox
|
JY-20808 low priority indexing queue by Vasil-Jimi JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app — Work...
|
1
|
github.com/jiminny/app/pull/12082/changes#diff-4a1 github.com/jiminny/app/pull/12082/changes#diff-4a1e0ff3a25c28615f1bf22dc2d6b441b1d1926a2befa1226494a7aed1aeef53...
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
Close tab
New Tab
Customize sidebar
Close Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
AI Chat settings
Close
WORK, Google Account: [EMAIL]
Main menu
New chat
Gemini
New Chat
Open menu for conversation actions.
Conversation with Gemini
Conversation with Gemini
Show the uploaded image in a lightbox
Copy prompt
You said Make a PR of changes Find potential issues and bottlenecks
You said
Make a PR of changes Find potential issues and bottlenecks
Listen
Show thinking
Gemini said
Gemini said
I can see you've uploaded a screenshot of a code diff, likely from a version control system given the red and green highlights. I would love to help you review the changes, spot bottlenecks, and help you draft a Pull Request.
However,
the image resolution is far too low for me to read.
It appears to be a completely zoomed-out view where the code has been reduced to tiny, illegible pixels. Because of this, I cannot extract any text or logic to analyze.
How You Can Share the Code
How You Can Share the Code
To help me review your code effectively, please try one of the following:
Paste the text directly:
Copy the specific code blocks (both the old and new versions if possible) and paste them directly into our chat.
Upload the files:
If the changes are extensive, you can upload the raw text or code files.
Take high-resolution screenshots:
If you must use images, take closer, readable screenshots of the specific functions or methods you want me to review.
Once you provide the readable code, I can dive right in to identify potential bugs, assess performance bottlenecks, and help you summarize the changes for your PR!
Good response
Bad response
Share & export
Copy
Show more options
Copy prompt
Edit
You said app/Component/ES/Listeners/UpdateMultipleTargetsListener.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\Component\ES\Listeners; namespace Jiminny\Component\ES\Listeners; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Contracts\ES\Events\UpdateMultipleEntities; use Jiminny\Contracts\ES\Events\UpdateMultipleEntities; use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface; AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntities(), $event->getEntities(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } } } app/Component/ES/Listeners/UpdateSingleTargetListener.php +9-1Lines changed: 9 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Actions\TrackElasticSearchOperations; use Jiminny\Component\ES\Actions\TrackElasticSearchOperations; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Contracts\ES\Events\UpdateSingleEntity; use Jiminny\Contracts\ES\Events\UpdateSingleEntity; use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface; 'entityId' => $event->getEntityId(), 'entityId' => $event->getEntityId(), ]); ]); /** * @important: * Synchronous event should eventually be deprecated. * Instant write operations are blocking and should be used sparingly. * It is much better in terms of performance to write 100 or 1000 documents at once, * and have one blocking reindex operation, instead of writing 10 documents synchronously. */ if ($event->isSyncEvent()) { if ($event->isSyncEvent()) { $this->handleSyncEvent($event); $this->handleSyncEvent($event); AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntityId(), $event->getEntityId(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } app/Component/ES/Processor/Actions/UpsertDocumentsAction.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SimpleCollection; use Jiminny\Component\ES\Processor\DTOs\SimpleCollection; use Jiminny\Component\ES\Processor\ResponseEvaluator; use Jiminny\Component\ES\Processor\ResponseEvaluator; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Exceptions\InvalidDataException; use Jiminny\Exceptions\InvalidDataException; use Sentry\Laravel\Facade as Sentry; use Sentry\Laravel\Facade as Sentry; AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( entityType: $this->updateTarget, entityType: $this->updateTarget, entityId: (int) $document->getId(), entityId: (int) $document->getId(), withPriority: true priority: QueuePriorityEnum::HIGH, ); ); } } app/Component/ES/Processor/DTOs/SelectionList.php +54-17Lines changed: 54 additions & 17 deletions Original file line numberOriginal file lineDiff line numberDiff line change namespace Jiminny\Component\ES\Processor\DTOs; namespace Jiminny\Component\ES\Processor\DTOs; use Jiminny\Component\ES\QueuePriorityEnum; /** /** * A very basic and simple collection of entity IDs. * A very basic and simple collection of entity IDs. */ */ class SelectionList class SelectionList { { public function __construct( private const int DEFAULT_CHUNK = 200; private readonly array $priorityEntityIdList = [], private readonly array $normalEntityIdList = [], private int $chunkSize = self::DEFAULT_CHUNK; private readonly bool $isStaleChunkSelected = false, private bool $isStaleChunkSelected = false; private readonly int $chunkSize = 200, private array $selectedEntityIds = []; ) { // Do nothing public function setChunkSize(int $chunkSize): void { $this->chunkSize = $chunkSize; } } public function getAllIds(): array public function markStale(): void { { return array_merge($this->priorityEntityIdList, $this->normalEntityIdList); $this->isStaleChunkSelected = true; } } public function count(): int public function addEntityList(string|QueuePriorityEnum $priority, array $entityIds): void { { return count($this->priorityEntityIdList) + count($this->normalEntityIdList); $priorityKey = $this->normalisePriority($priority); if (! array_key_exists($priorityKey, $this->selectedEntityIds)) { $this->selectedEntityIds[$priorityKey] = []; } $this->selectedEntityIds[$priorityKey] = array_merge($this->selectedEntityIds[$priorityKey], $entityIds); } } public function isEmpty(): bool /** * @return string[] */ public function getEntityListGroups(): array { { return empty($this->priorityEntityIdList) && empty($this->normalEntityIdList); return array_keys($this->selectedEntityIds); } } public function getHighPriorityEntityIds(): array public function getEntityListItemsByGroup(string|QueuePriorityEnum $priority): array { { return $this->priorityEntityIdList; $priorityKey = $this->normalisePriority($priority); return $this->selectedEntityIds[$priorityKey] ?? []; } } public function getNormalPriorityEntityId(): array public function getAllIds(): array { { return $this->normalEntityIdList; $allIds = []; foreach ($this->selectedEntityIds as $entityIds) { $allIds = array_merge($allIds, $entityIds); } return $allIds; } public function count(): int { return array_sum( array_map('count', $this->selectedEntityIds) ); } public function isEmpty(): bool { return $this->count() === 0; } } public function isStaleChunkSelected(): bool public function isStaleChunkSelected(): bool { { return $this->count() >= $this->chunkSize; return $this->count() >= $this->chunkSize; } } private function normalisePriority(string|QueuePriorityEnum $priority): string { return $priority instanceof QueuePriorityEnum ? $priority->value : $priority; } } } app/Component/ES/Processor/Traits/SelectEntityListTrait.php +27-4Lines changed: 27 additions & 4 deletions Original file line numberOriginal file lineDiff line numberDiff line change use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; /** /** * Build the correct source list name for the type of entity and priority * Build the correct source list name for the type of entity and priority */ */ trait SelectEntityListTrait trait SelectEntityListTrait { { /** * Highest priority queue for data requiring near-instant availability. * Very few entities should be added here, only when absolutely necessary. */ private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; /** * Normal priority queue for normal application operations. * Almost all update events should pass through this queue */ private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; protected static function selectTargetList(string $entityType, bool $withPriority = false): string /** { * Nonblocking low priority queue. This queue will be consumed only when there is nothing * with higher priority. * * This queue will be used for operations such as es:reset-async */ private const string ENTITIES_LOW_PRIORITIES_LIST = '%s-for-update-low'; protected static function selectTargetList( string $entityType, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { if (! in_array($entityType, UpdateTarget::allowedTargets())) { if (! in_array($entityType, UpdateTarget::allowedTargets())) { throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); } } if ($withPriority) { if ($priority->isHigh()) { Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); } } if ($priority->isLow()) { return sprintf(self::ENTITIES_LOW_PRIORITIES_LIST, $entityType); } return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); } } } } app/Component/ES/Processor/TargetEntitiesSelector.php +26-21Lines changed: 26 additions & 21 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SelectionList; use Jiminny\Component\ES\Processor\DTOs\SelectionList; use Jiminny\Component\ES\Processor\Traits\ExtractIdsTrait; use Jiminny\Component\ES\Processor\Traits\ExtractIdsTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\QueuePriorityEnum; /** /** * This class supplies a list of entities pending an update. * This class supplies a list of entities pending an update. public function select(): SelectionList public function select(): SelectionList { { $staleWorkEntityIds = $this->getStaleChunk(); $selectionList = new SelectionList(); $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $staleWorkEntityIds = $this->getStaleChunk(); if (count($staleWorkEntityIds) > 0) { if (count($staleWorkEntityIds) > 0) { return new SelectionList( /** priorityEntityIdList: $staleWorkEntityIds, * Stale chunks are treated as high priority isStaleChunkSelected: true, */ chunkSize: ChunkSize::getStaleChunkSize($this->updateTarget), $selectionList->markStale(); ); $selectionList->addEntityList(QueuePriorityEnum::HIGH, $staleWorkEntityIds); $selectionList->setChunkSize(ChunkSize::getStaleChunkSize($this->updateTarget)); return $selectionList; } } $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $selectionList->setChunkSize($mainChunkSize); $priorityEntityIdsList = $this->extractIdsFromSet( $priorityEntityIdsList = $this->extractIds(QueuePriorityEnum::HIGH, $mainChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, true), $selectionList->addEntityList(QueuePriorityEnum::HIGH, $priorityEntityIdsList); $mainChunkSize, ); $normalEntityIdsList = []; $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); if ($normalEntityChunkSize > 0) { if ($normalEntityChunkSize > 0) { $normalEntityIdsList = $this->extractIdsFromSet( $normalEntityIdsList = $this->extractIds(QueuePriorityEnum::NORMAL, $normalEntityChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, false), $selectionList->addEntityList(QueuePriorityEnum::NORMAL, $normalEntityIdsList); $normalEntityChunkSize ); } } return new SelectionList( return $selectionList; priorityEntityIdList: $priorityEntityIdsList, normalEntityIdList: $normalEntityIdsList, chunkSize: $mainChunkSize ); } } private function getStaleChunk(): array private function getStaleChunk(): array return []; return []; } } private function extractIds(QueuePriorityEnum $priority, int $chunkSize): array { return $this->extractIdsFromSet( AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, $priority), $chunkSize ); } } } app/Component/ES/AsyncUpdateElasticSearch.php +17-10Lines changed: 17 additions & 10 deletions Original file line numberOriginal file lineDiff line numberDiff line change * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * and other activity related data * and other activity related data */ */ public static function markEntityForUpdate(string $entityType, int $entityId, bool $withPriority = false): void public static function markEntityForUpdate( { string $entityType, $targetList = self::selectTargetList($entityType, $withPriority); int $entityId, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { $targetList = self::selectTargetList($entityType, $priority); Redis::sadd($targetList, $entityId); Redis::sadd($targetList, $entityId); Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ 'entityType' => $entityType, 'entityType' => $entityType, 'entityId' => $entityId, 'entityId' => $entityId, 'collectionKey' => $targetList, 'collectionKey' => $targetList, 'withPriority' => $withPriority, 'priority' => $priority->value, ]); ]); } } public static function bulkMarkEntitiesForUpdate( public static function bulkMarkEntitiesForUpdate( string $entityType, string $entityType, array $entityIds, array $entityIds, bool $withPriority = false QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { ): void { if (empty($entityIds)) { if (empty($entityIds)) { return; return; } } $targetList = self::selectTargetList($entityType, $withPriority); $targetList = self::selectTargetList($entityType, $priority); Redis::saddarray($targetList, $entityIds); Redis::saddarray($targetList, $entityIds); } } * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Takes priority into consideration. * Takes priority into consideration. */ */ public static function getEntitiesSourceList(string $updateTarget, $priority = false): string public static function getEntitiesSourceList( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { return self::selectTargetList($updateTarget, $priority); return self::selectTargetList($updateTarget, $priority); } } /** /** * Externally called helper methods * Externally called helper methods * - count and flush * - count and flush */ */ public static function getEntitiesListCount(string $updateTarget, $priority = false): int public static function getEntitiesListCount( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): int { $targetList = self::selectTargetList($updateTarget, $priority); $targetList = self::selectTargetList($updateTarget, $priority); return Redis::scard($targetList); return Redis::scard($targetList); app/Component/ES/QueuePriorityEnum.php +40Lines changed: 40 additions & 0 deletions Original file line numberOriginal file lineDiff line numberDiff line change <?php declare(strict_types=1); namespace Jiminny\Component\ES; use Jiminny\Exceptions\InvalidArgumentException; enum QueuePriorityEnum: string { case HIGH = 'high'; case NORMAL = 'normal'; case LOW = 'low'; public static function tryFromString(string $value): self { if (! self::isValid($value)) { throw new InvalidArgumentException( sprintf('Invalid queue priority "%s" selected', $value) ); } return self::tryFrom($value); } public static function isValid(string $value): bool { return self::tryFrom($value) !== null; } public function isLow(): bool { return $this === self::LOW; } public function isHigh(): bool { return $this === self::HIGH; } } app/Component/ES/UpdateProcessManager.php +12-9Lines changed: 12 additions & 9 deletions Original file line numberOriginal file lineDiff line numberDiff line change if ($selectionList->isEmpty()) { if ($selectionList->isEmpty()) { return false; return false; } } /** /** * A stale chunk will always be smaller than a regular chunk. * A stale chunk will always be smaller than a regular chunk. * That doesn't mean there aren't any other scheduled entities for processing * That doesn't mean there aren't any other scheduled entities for processing private function rescheduleThrottledEntities(SelectionList $selectionList): void private function rescheduleThrottledEntities(SelectionList $selectionList): void { { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $groups = $selectionList->getEntityListGroups(); $this->updateTarget, foreach ($groups as $eachGroup) { $selectionList->getNormalPriorityEntityId() $groupEntityIds = $selectionList->getEntityListItemsByGroup($eachGroup); ); if (! empty($groupEntityIds)) { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $this->updateTarget, entityType: $this->updateTarget, $selectionList->getHighPriorityEntityIds(), entityIds: $groupEntityIds, true priority: QueuePriorityEnum::tryFromString($eachGroup) ); ); } } } } } } app/Console/Commands/Elasticsearch/AsyncUpdateEsEntities.php +9-3Lines changed: 9 additions & 3 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Illuminate\Support\Str; use Illuminate\Support\Str; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Component\ES\UpdateProcessManager; use Jiminny\Component\ES\UpdateProcessManager; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Traits\GracefullyStoppable; use Jiminny\Traits\GracefullyStoppable; Redis::set($gaugeLockName, true); Redis::set($gaugeLockName, true); Redis::expire($gaugeLockName, 60); Redis::expire($gaugeLockName, 60); $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::HIGH), ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update', $updateTarget), stat: sprintf('jiminny.%s-for-update', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::NORMAL), ); ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), stat: sprintf('jiminny.%s-for-update-low', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, true), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::LOW), ); ); } } app/Console/Commands/Elasticsearch/ResetAsyncElasticSearchCommand.php +5-1Lines changed: 5 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\Traits\ValidateUpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\ValidateUpdateTargetTrait; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Component\ES\Repositories\EsResetRepositoryInterface; use Jiminny\Component\ES\Repositories\EsResetRepositoryInterface; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Traits\GracefullyStoppable; use Jiminny\Traits\GracefullyStoppable; private function getRemainingScheduledEntities(bool $printStatus = false): int private function getRemainingScheduledEntities(bool $printStatus = false): int { { $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget, true); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount( $this->updateTarget, QueuePriorityEnum::HIGH ); if ($printStatus) { if ($printStatus) { $this->line( $this->line(
You said
app/Component/ES/Listeners/UpdateMultipleTargetsListener.php
+2-1Lines changed: 2 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\Component\ES\Listeners;
namespace Jiminny\Component\ES\Listeners;...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New Tab","depth":4,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Close Google Gemini (⌃X)","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Tabs from other devices","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"AI Chat settings","depth":7,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Close","depth":7,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"WORK, Google Account: lukas.kovalik@jiminny.com","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Main menu","depth":12,"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New chat","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Gemini","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"New Chat","depth":12,"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Open menu for conversation actions.","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXHeading","text":"Conversation with Gemini","depth":15,"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Conversation with Gemini","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Show the uploaded image in a lightbox","depth":21,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy prompt","depth":21,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"You said Make a PR of changes Find potential issues and bottlenecks","depth":21,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"You said","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Make a PR of changes Find potential issues and bottlenecks","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Listen","depth":22,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Show thinking","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Gemini said","depth":20,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Gemini said","depth":21,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"I can see you've uploaded a screenshot of a code diff, likely from a version control system given the red and green highlights. I would love to help you review the changes, spot bottlenecks, and help you draft a Pull Request.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"However,","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"the image resolution is far too low for me to read.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"It appears to be a completely zoomed-out view where the code has been reduced to tiny, illegible pixels. Because of this, I cannot extract any text or logic to analyze.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"How You Can Share the Code","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"How You Can Share the Code","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"To help me review your code effectively, please try one of the following:","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Paste the text directly:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Copy the specific code blocks (both the old and new versions if possible) and paste them directly into our chat.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Upload the files:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"If the changes are extensive, you can upload the raw text or code files.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Take high-resolution screenshots:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"If you must use images, take closer, readable screenshots of the specific functions or methods you want me to review.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Once you provide the readable code, I can dive right in to identify potential bugs, assess performance bottlenecks, and help you summarize the changes for your PR!","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Good response","depth":22,"on_screen":false,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Bad response","depth":22,"on_screen":false,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Share & export","depth":21,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy","depth":22,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Show more options","depth":21,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy prompt","depth":21,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Edit","depth":21,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"You said app/Component/ES/Listeners/UpdateMultipleTargetsListener.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\\Component\\ES\\Listeners; namespace Jiminny\\Component\\ES\\Listeners; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Contracts\\ES\\Events\\UpdateMultipleEntities; use Jiminny\\Contracts\\ES\\Events\\UpdateMultipleEntities; use Psr\\Log\\LoggerInterface; use Psr\\Log\\LoggerInterface; AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntities(), $event->getEntities(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } } } app/Component/ES/Listeners/UpdateSingleTargetListener.php +9-1Lines changed: 9 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Actions\\TrackElasticSearchOperations; use Jiminny\\Component\\ES\\Actions\\TrackElasticSearchOperations; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder; use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Contracts\\ES\\Events\\UpdateSingleEntity; use Jiminny\\Contracts\\ES\\Events\\UpdateSingleEntity; use Psr\\Log\\LoggerInterface; use Psr\\Log\\LoggerInterface; 'entityId' => $event->getEntityId(), 'entityId' => $event->getEntityId(), ]); ]); /** * @important: * Synchronous event should eventually be deprecated. * Instant write operations are blocking and should be used sparingly. * It is much better in terms of performance to write 100 or 1000 documents at once, * and have one blocking reindex operation, instead of writing 10 documents synchronously. */ if ($event->isSyncEvent()) { if ($event->isSyncEvent()) { $this->handleSyncEvent($event); $this->handleSyncEvent($event); AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntityId(), $event->getEntityId(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } app/Component/ES/Processor/Actions/UpsertDocumentsAction.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Processor\\DTOs\\SimpleCollection; use Jiminny\\Component\\ES\\Processor\\DTOs\\SimpleCollection; use Jiminny\\Component\\ES\\Processor\\ResponseEvaluator; use Jiminny\\Component\\ES\\Processor\\ResponseEvaluator; use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait; use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Exceptions\\InvalidDataException; use Jiminny\\Exceptions\\InvalidDataException; use Sentry\\Laravel\\Facade as Sentry; use Sentry\\Laravel\\Facade as Sentry; AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( entityType: $this->updateTarget, entityType: $this->updateTarget, entityId: (int) $document->getId(), entityId: (int) $document->getId(), withPriority: true priority: QueuePriorityEnum::HIGH, ); ); } } app/Component/ES/Processor/DTOs/SelectionList.php +54-17Lines changed: 54 additions & 17 deletions Original file line numberOriginal file lineDiff line numberDiff line change namespace Jiminny\\Component\\ES\\Processor\\DTOs; namespace Jiminny\\Component\\ES\\Processor\\DTOs; use Jiminny\\Component\\ES\\QueuePriorityEnum; /** /** * A very basic and simple collection of entity IDs. * A very basic and simple collection of entity IDs. */ */ class SelectionList class SelectionList { { public function __construct( private const int DEFAULT_CHUNK = 200; private readonly array $priorityEntityIdList = [], private readonly array $normalEntityIdList = [], private int $chunkSize = self::DEFAULT_CHUNK; private readonly bool $isStaleChunkSelected = false, private bool $isStaleChunkSelected = false; private readonly int $chunkSize = 200, private array $selectedEntityIds = []; ) { // Do nothing public function setChunkSize(int $chunkSize): void { $this->chunkSize = $chunkSize; } } public function getAllIds(): array public function markStale(): void { { return array_merge($this->priorityEntityIdList, $this->normalEntityIdList); $this->isStaleChunkSelected = true; } } public function count(): int public function addEntityList(string|QueuePriorityEnum $priority, array $entityIds): void { { return count($this->priorityEntityIdList) + count($this->normalEntityIdList); $priorityKey = $this->normalisePriority($priority); if (! array_key_exists($priorityKey, $this->selectedEntityIds)) { $this->selectedEntityIds[$priorityKey] = []; } $this->selectedEntityIds[$priorityKey] = array_merge($this->selectedEntityIds[$priorityKey], $entityIds); } } public function isEmpty(): bool /** * @return string[] */ public function getEntityListGroups(): array { { return empty($this->priorityEntityIdList) && empty($this->normalEntityIdList); return array_keys($this->selectedEntityIds); } } public function getHighPriorityEntityIds(): array public function getEntityListItemsByGroup(string|QueuePriorityEnum $priority): array { { return $this->priorityEntityIdList; $priorityKey = $this->normalisePriority($priority); return $this->selectedEntityIds[$priorityKey] ?? []; } } public function getNormalPriorityEntityId(): array public function getAllIds(): array { { return $this->normalEntityIdList; $allIds = []; foreach ($this->selectedEntityIds as $entityIds) { $allIds = array_merge($allIds, $entityIds); } return $allIds; } public function count(): int { return array_sum( array_map('count', $this->selectedEntityIds) ); } public function isEmpty(): bool { return $this->count() === 0; } } public function isStaleChunkSelected(): bool public function isStaleChunkSelected(): bool { { return $this->count() >= $this->chunkSize; return $this->count() >= $this->chunkSize; } } private function normalisePriority(string|QueuePriorityEnum $priority): string { return $priority instanceof QueuePriorityEnum ? $priority->value : $priority; } } } app/Component/ES/Processor/Traits/SelectEntityListTrait.php +27-4Lines changed: 27 additions & 4 deletions Original file line numberOriginal file lineDiff line numberDiff line change use Illuminate\\Support\\Facades\\Log; use Illuminate\\Support\\Facades\\Log; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Exceptions\\InvalidArgumentException; use Jiminny\\Exceptions\\InvalidArgumentException; /** /** * Build the correct source list name for the type of entity and priority * Build the correct source list name for the type of entity and priority */ */ trait SelectEntityListTrait trait SelectEntityListTrait { { /** * Highest priority queue for data requiring near-instant availability. * Very few entities should be added here, only when absolutely necessary. */ private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; /** * Normal priority queue for normal application operations. * Almost all update events should pass through this queue */ private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; protected static function selectTargetList(string $entityType, bool $withPriority = false): string /** { * Nonblocking low priority queue. This queue will be consumed only when there is nothing * with higher priority. * * This queue will be used for operations such as es:reset-async */ private const string ENTITIES_LOW_PRIORITIES_LIST = '%s-for-update-low'; protected static function selectTargetList( string $entityType, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { if (! in_array($entityType, UpdateTarget::allowedTargets())) { if (! in_array($entityType, UpdateTarget::allowedTargets())) { throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); } } if ($withPriority) { if ($priority->isHigh()) { Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); } } if ($priority->isLow()) { return sprintf(self::ENTITIES_LOW_PRIORITIES_LIST, $entityType); } return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); } } } } app/Component/ES/Processor/TargetEntitiesSelector.php +26-21Lines changed: 26 additions & 21 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Processor\\DTOs\\SelectionList; use Jiminny\\Component\\ES\\Processor\\DTOs\\SelectionList; use Jiminny\\Component\\ES\\Processor\\Traits\\ExtractIdsTrait; use Jiminny\\Component\\ES\\Processor\\Traits\\ExtractIdsTrait; use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait; use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait; use Jiminny\\Component\\ES\\QueuePriorityEnum; /** /** * This class supplies a list of entities pending an update. * This class supplies a list of entities pending an update. public function select(): SelectionList public function select(): SelectionList { { $staleWorkEntityIds = $this->getStaleChunk(); $selectionList = new SelectionList(); $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $staleWorkEntityIds = $this->getStaleChunk(); if (count($staleWorkEntityIds) > 0) { if (count($staleWorkEntityIds) > 0) { return new SelectionList( /** priorityEntityIdList: $staleWorkEntityIds, * Stale chunks are treated as high priority isStaleChunkSelected: true, */ chunkSize: ChunkSize::getStaleChunkSize($this->updateTarget), $selectionList->markStale(); ); $selectionList->addEntityList(QueuePriorityEnum::HIGH, $staleWorkEntityIds); $selectionList->setChunkSize(ChunkSize::getStaleChunkSize($this->updateTarget)); return $selectionList; } } $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $selectionList->setChunkSize($mainChunkSize); $priorityEntityIdsList = $this->extractIdsFromSet( $priorityEntityIdsList = $this->extractIds(QueuePriorityEnum::HIGH, $mainChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, true), $selectionList->addEntityList(QueuePriorityEnum::HIGH, $priorityEntityIdsList); $mainChunkSize, ); $normalEntityIdsList = []; $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); if ($normalEntityChunkSize > 0) { if ($normalEntityChunkSize > 0) { $normalEntityIdsList = $this->extractIdsFromSet( $normalEntityIdsList = $this->extractIds(QueuePriorityEnum::NORMAL, $normalEntityChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, false), $selectionList->addEntityList(QueuePriorityEnum::NORMAL, $normalEntityIdsList); $normalEntityChunkSize ); } } return new SelectionList( return $selectionList; priorityEntityIdList: $priorityEntityIdsList, normalEntityIdList: $normalEntityIdsList, chunkSize: $mainChunkSize ); } } private function getStaleChunk(): array private function getStaleChunk(): array return []; return []; } } private function extractIds(QueuePriorityEnum $priority, int $chunkSize): array { return $this->extractIdsFromSet( AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, $priority), $chunkSize ); } } } app/Component/ES/AsyncUpdateElasticSearch.php +17-10Lines changed: 17 additions & 10 deletions Original file line numberOriginal file lineDiff line numberDiff line change * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * and other activity related data * and other activity related data */ */ public static function markEntityForUpdate(string $entityType, int $entityId, bool $withPriority = false): void public static function markEntityForUpdate( { string $entityType, $targetList = self::selectTargetList($entityType, $withPriority); int $entityId, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { $targetList = self::selectTargetList($entityType, $priority); Redis::sadd($targetList, $entityId); Redis::sadd($targetList, $entityId); Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ 'entityType' => $entityType, 'entityType' => $entityType, 'entityId' => $entityId, 'entityId' => $entityId, 'collectionKey' => $targetList, 'collectionKey' => $targetList, 'withPriority' => $withPriority, 'priority' => $priority->value, ]); ]); } } public static function bulkMarkEntitiesForUpdate( public static function bulkMarkEntitiesForUpdate( string $entityType, string $entityType, array $entityIds, array $entityIds, bool $withPriority = false QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { ): void { if (empty($entityIds)) { if (empty($entityIds)) { return; return; } } $targetList = self::selectTargetList($entityType, $withPriority); $targetList = self::selectTargetList($entityType, $priority); Redis::saddarray($targetList, $entityIds); Redis::saddarray($targetList, $entityIds); } } * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Takes priority into consideration. * Takes priority into consideration. */ */ public static function getEntitiesSourceList(string $updateTarget, $priority = false): string public static function getEntitiesSourceList( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { return self::selectTargetList($updateTarget, $priority); return self::selectTargetList($updateTarget, $priority); } } /** /** * Externally called helper methods * Externally called helper methods * - count and flush * - count and flush */ */ public static function getEntitiesListCount(string $updateTarget, $priority = false): int public static function getEntitiesListCount( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): int { $targetList = self::selectTargetList($updateTarget, $priority); $targetList = self::selectTargetList($updateTarget, $priority); return Redis::scard($targetList); return Redis::scard($targetList); app/Component/ES/QueuePriorityEnum.php +40Lines changed: 40 additions & 0 deletions Original file line numberOriginal file lineDiff line numberDiff line change <?php declare(strict_types=1); namespace Jiminny\\Component\\ES; use Jiminny\\Exceptions\\InvalidArgumentException; enum QueuePriorityEnum: string { case HIGH = 'high'; case NORMAL = 'normal'; case LOW = 'low'; public static function tryFromString(string $value): self { if (! self::isValid($value)) { throw new InvalidArgumentException( sprintf('Invalid queue priority \"%s\" selected', $value) ); } return self::tryFrom($value); } public static function isValid(string $value): bool { return self::tryFrom($value) !== null; } public function isLow(): bool { return $this === self::LOW; } public function isHigh(): bool { return $this === self::HIGH; } } app/Component/ES/UpdateProcessManager.php +12-9Lines changed: 12 additions & 9 deletions Original file line numberOriginal file lineDiff line numberDiff line change if ($selectionList->isEmpty()) { if ($selectionList->isEmpty()) { return false; return false; } } /** /** * A stale chunk will always be smaller than a regular chunk. * A stale chunk will always be smaller than a regular chunk. * That doesn't mean there aren't any other scheduled entities for processing * That doesn't mean there aren't any other scheduled entities for processing private function rescheduleThrottledEntities(SelectionList $selectionList): void private function rescheduleThrottledEntities(SelectionList $selectionList): void { { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $groups = $selectionList->getEntityListGroups(); $this->updateTarget, foreach ($groups as $eachGroup) { $selectionList->getNormalPriorityEntityId() $groupEntityIds = $selectionList->getEntityListItemsByGroup($eachGroup); ); if (! empty($groupEntityIds)) { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $this->updateTarget, entityType: $this->updateTarget, $selectionList->getHighPriorityEntityIds(), entityIds: $groupEntityIds, true priority: QueuePriorityEnum::tryFromString($eachGroup) ); ); } } } } } } app/Console/Commands/Elasticsearch/AsyncUpdateEsEntities.php +9-3Lines changed: 9 additions & 3 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Illuminate\\Support\\Str; use Illuminate\\Support\\Str; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Component\\ES\\UpdateProcessManager; use Jiminny\\Component\\ES\\UpdateProcessManager; use Jiminny\\Exceptions\\InvalidArgumentException; use Jiminny\\Exceptions\\InvalidArgumentException; use Jiminny\\Traits\\GracefullyStoppable; use Jiminny\\Traits\\GracefullyStoppable; Redis::set($gaugeLockName, true); Redis::set($gaugeLockName, true); Redis::expire($gaugeLockName, 60); Redis::expire($gaugeLockName, 60); $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::HIGH), ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update', $updateTarget), stat: sprintf('jiminny.%s-for-update', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::NORMAL), ); ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), stat: sprintf('jiminny.%s-for-update-low', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, true), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::LOW), ); ); } } app/Console/Commands/Elasticsearch/ResetAsyncElasticSearchCommand.php +5-1Lines changed: 5 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder; use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder; use Jiminny\\Component\\ES\\Processor\\Traits\\ValidateUpdateTargetTrait; use Jiminny\\Component\\ES\\Processor\\Traits\\ValidateUpdateTargetTrait; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Component\\ES\\Repositories\\EsResetRepositoryInterface; use Jiminny\\Component\\ES\\Repositories\\EsResetRepositoryInterface; use Jiminny\\Exceptions\\InvalidArgumentException; use Jiminny\\Exceptions\\InvalidArgumentException; use Jiminny\\Traits\\GracefullyStoppable; use Jiminny\\Traits\\GracefullyStoppable; private function getRemainingScheduledEntities(bool $printStatus = false): int private function getRemainingScheduledEntities(bool $printStatus = false): int { { $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget, true); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount( $this->updateTarget, QueuePriorityEnum::HIGH ); if ($printStatus) { if ($printStatus) { $this->line( $this->line(","depth":21,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"You said","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app/Component/ES/Listeners/UpdateMultipleTargetsListener.php","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"+2-1Lines changed: 2 additions & 1 deletion","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\\Component\\ES\\Listeners;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"namespace Jiminny\\Component\\ES\\Listeners;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"}]...
|
-3584876229358006207
|
-1127563132028511090
|
click
|
accessibility
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
Close tab
New Tab
Customize sidebar
Close Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
AI Chat settings
Close
WORK, Google Account: [EMAIL]
Main menu
New chat
Gemini
New Chat
Open menu for conversation actions.
Conversation with Gemini
Conversation with Gemini
Show the uploaded image in a lightbox
Copy prompt
You said Make a PR of changes Find potential issues and bottlenecks
You said
Make a PR of changes Find potential issues and bottlenecks
Listen
Show thinking
Gemini said
Gemini said
I can see you've uploaded a screenshot of a code diff, likely from a version control system given the red and green highlights. I would love to help you review the changes, spot bottlenecks, and help you draft a Pull Request.
However,
the image resolution is far too low for me to read.
It appears to be a completely zoomed-out view where the code has been reduced to tiny, illegible pixels. Because of this, I cannot extract any text or logic to analyze.
How You Can Share the Code
How You Can Share the Code
To help me review your code effectively, please try one of the following:
Paste the text directly:
Copy the specific code blocks (both the old and new versions if possible) and paste them directly into our chat.
Upload the files:
If the changes are extensive, you can upload the raw text or code files.
Take high-resolution screenshots:
If you must use images, take closer, readable screenshots of the specific functions or methods you want me to review.
Once you provide the readable code, I can dive right in to identify potential bugs, assess performance bottlenecks, and help you summarize the changes for your PR!
Good response
Bad response
Share & export
Copy
Show more options
Copy prompt
Edit
You said app/Component/ES/Listeners/UpdateMultipleTargetsListener.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\Component\ES\Listeners; namespace Jiminny\Component\ES\Listeners; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Contracts\ES\Events\UpdateMultipleEntities; use Jiminny\Contracts\ES\Events\UpdateMultipleEntities; use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface; AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntities(), $event->getEntities(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } } } app/Component/ES/Listeners/UpdateSingleTargetListener.php +9-1Lines changed: 9 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Actions\TrackElasticSearchOperations; use Jiminny\Component\ES\Actions\TrackElasticSearchOperations; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Contracts\ES\Events\UpdateSingleEntity; use Jiminny\Contracts\ES\Events\UpdateSingleEntity; use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface; 'entityId' => $event->getEntityId(), 'entityId' => $event->getEntityId(), ]); ]); /** * @important: * Synchronous event should eventually be deprecated. * Instant write operations are blocking and should be used sparingly. * It is much better in terms of performance to write 100 or 1000 documents at once, * and have one blocking reindex operation, instead of writing 10 documents synchronously. */ if ($event->isSyncEvent()) { if ($event->isSyncEvent()) { $this->handleSyncEvent($event); $this->handleSyncEvent($event); AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntityId(), $event->getEntityId(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } app/Component/ES/Processor/Actions/UpsertDocumentsAction.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SimpleCollection; use Jiminny\Component\ES\Processor\DTOs\SimpleCollection; use Jiminny\Component\ES\Processor\ResponseEvaluator; use Jiminny\Component\ES\Processor\ResponseEvaluator; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Exceptions\InvalidDataException; use Jiminny\Exceptions\InvalidDataException; use Sentry\Laravel\Facade as Sentry; use Sentry\Laravel\Facade as Sentry; AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( entityType: $this->updateTarget, entityType: $this->updateTarget, entityId: (int) $document->getId(), entityId: (int) $document->getId(), withPriority: true priority: QueuePriorityEnum::HIGH, ); ); } } app/Component/ES/Processor/DTOs/SelectionList.php +54-17Lines changed: 54 additions & 17 deletions Original file line numberOriginal file lineDiff line numberDiff line change namespace Jiminny\Component\ES\Processor\DTOs; namespace Jiminny\Component\ES\Processor\DTOs; use Jiminny\Component\ES\QueuePriorityEnum; /** /** * A very basic and simple collection of entity IDs. * A very basic and simple collection of entity IDs. */ */ class SelectionList class SelectionList { { public function __construct( private const int DEFAULT_CHUNK = 200; private readonly array $priorityEntityIdList = [], private readonly array $normalEntityIdList = [], private int $chunkSize = self::DEFAULT_CHUNK; private readonly bool $isStaleChunkSelected = false, private bool $isStaleChunkSelected = false; private readonly int $chunkSize = 200, private array $selectedEntityIds = []; ) { // Do nothing public function setChunkSize(int $chunkSize): void { $this->chunkSize = $chunkSize; } } public function getAllIds(): array public function markStale(): void { { return array_merge($this->priorityEntityIdList, $this->normalEntityIdList); $this->isStaleChunkSelected = true; } } public function count(): int public function addEntityList(string|QueuePriorityEnum $priority, array $entityIds): void { { return count($this->priorityEntityIdList) + count($this->normalEntityIdList); $priorityKey = $this->normalisePriority($priority); if (! array_key_exists($priorityKey, $this->selectedEntityIds)) { $this->selectedEntityIds[$priorityKey] = []; } $this->selectedEntityIds[$priorityKey] = array_merge($this->selectedEntityIds[$priorityKey], $entityIds); } } public function isEmpty(): bool /** * @return string[] */ public function getEntityListGroups(): array { { return empty($this->priorityEntityIdList) && empty($this->normalEntityIdList); return array_keys($this->selectedEntityIds); } } public function getHighPriorityEntityIds(): array public function getEntityListItemsByGroup(string|QueuePriorityEnum $priority): array { { return $this->priorityEntityIdList; $priorityKey = $this->normalisePriority($priority); return $this->selectedEntityIds[$priorityKey] ?? []; } } public function getNormalPriorityEntityId(): array public function getAllIds(): array { { return $this->normalEntityIdList; $allIds = []; foreach ($this->selectedEntityIds as $entityIds) { $allIds = array_merge($allIds, $entityIds); } return $allIds; } public function count(): int { return array_sum( array_map('count', $this->selectedEntityIds) ); } public function isEmpty(): bool { return $this->count() === 0; } } public function isStaleChunkSelected(): bool public function isStaleChunkSelected(): bool { { return $this->count() >= $this->chunkSize; return $this->count() >= $this->chunkSize; } } private function normalisePriority(string|QueuePriorityEnum $priority): string { return $priority instanceof QueuePriorityEnum ? $priority->value : $priority; } } } app/Component/ES/Processor/Traits/SelectEntityListTrait.php +27-4Lines changed: 27 additions & 4 deletions Original file line numberOriginal file lineDiff line numberDiff line change use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; /** /** * Build the correct source list name for the type of entity and priority * Build the correct source list name for the type of entity and priority */ */ trait SelectEntityListTrait trait SelectEntityListTrait { { /** * Highest priority queue for data requiring near-instant availability. * Very few entities should be added here, only when absolutely necessary. */ private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; /** * Normal priority queue for normal application operations. * Almost all update events should pass through this queue */ private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; protected static function selectTargetList(string $entityType, bool $withPriority = false): string /** { * Nonblocking low priority queue. This queue will be consumed only when there is nothing * with higher priority. * * This queue will be used for operations such as es:reset-async */ private const string ENTITIES_LOW_PRIORITIES_LIST = '%s-for-update-low'; protected static function selectTargetList( string $entityType, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { if (! in_array($entityType, UpdateTarget::allowedTargets())) { if (! in_array($entityType, UpdateTarget::allowedTargets())) { throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); } } if ($withPriority) { if ($priority->isHigh()) { Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); } } if ($priority->isLow()) { return sprintf(self::ENTITIES_LOW_PRIORITIES_LIST, $entityType); } return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); } } } } app/Component/ES/Processor/TargetEntitiesSelector.php +26-21Lines changed: 26 additions & 21 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SelectionList; use Jiminny\Component\ES\Processor\DTOs\SelectionList; use Jiminny\Component\ES\Processor\Traits\ExtractIdsTrait; use Jiminny\Component\ES\Processor\Traits\ExtractIdsTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\QueuePriorityEnum; /** /** * This class supplies a list of entities pending an update. * This class supplies a list of entities pending an update. public function select(): SelectionList public function select(): SelectionList { { $staleWorkEntityIds = $this->getStaleChunk(); $selectionList = new SelectionList(); $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $staleWorkEntityIds = $this->getStaleChunk(); if (count($staleWorkEntityIds) > 0) { if (count($staleWorkEntityIds) > 0) { return new SelectionList( /** priorityEntityIdList: $staleWorkEntityIds, * Stale chunks are treated as high priority isStaleChunkSelected: true, */ chunkSize: ChunkSize::getStaleChunkSize($this->updateTarget), $selectionList->markStale(); ); $selectionList->addEntityList(QueuePriorityEnum::HIGH, $staleWorkEntityIds); $selectionList->setChunkSize(ChunkSize::getStaleChunkSize($this->updateTarget)); return $selectionList; } } $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $selectionList->setChunkSize($mainChunkSize); $priorityEntityIdsList = $this->extractIdsFromSet( $priorityEntityIdsList = $this->extractIds(QueuePriorityEnum::HIGH, $mainChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, true), $selectionList->addEntityList(QueuePriorityEnum::HIGH, $priorityEntityIdsList); $mainChunkSize, ); $normalEntityIdsList = []; $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); if ($normalEntityChunkSize > 0) { if ($normalEntityChunkSize > 0) { $normalEntityIdsList = $this->extractIdsFromSet( $normalEntityIdsList = $this->extractIds(QueuePriorityEnum::NORMAL, $normalEntityChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, false), $selectionList->addEntityList(QueuePriorityEnum::NORMAL, $normalEntityIdsList); $normalEntityChunkSize ); } } return new SelectionList( return $selectionList; priorityEntityIdList: $priorityEntityIdsList, normalEntityIdList: $normalEntityIdsList, chunkSize: $mainChunkSize ); } } private function getStaleChunk(): array private function getStaleChunk(): array return []; return []; } } private function extractIds(QueuePriorityEnum $priority, int $chunkSize): array { return $this->extractIdsFromSet( AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, $priority), $chunkSize ); } } } app/Component/ES/AsyncUpdateElasticSearch.php +17-10Lines changed: 17 additions & 10 deletions Original file line numberOriginal file lineDiff line numberDiff line change * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * and other activity related data * and other activity related data */ */ public static function markEntityForUpdate(string $entityType, int $entityId, bool $withPriority = false): void public static function markEntityForUpdate( { string $entityType, $targetList = self::selectTargetList($entityType, $withPriority); int $entityId, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { $targetList = self::selectTargetList($entityType, $priority); Redis::sadd($targetList, $entityId); Redis::sadd($targetList, $entityId); Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ 'entityType' => $entityType, 'entityType' => $entityType, 'entityId' => $entityId, 'entityId' => $entityId, 'collectionKey' => $targetList, 'collectionKey' => $targetList, 'withPriority' => $withPriority, 'priority' => $priority->value, ]); ]); } } public static function bulkMarkEntitiesForUpdate( public static function bulkMarkEntitiesForUpdate( string $entityType, string $entityType, array $entityIds, array $entityIds, bool $withPriority = false QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { ): void { if (empty($entityIds)) { if (empty($entityIds)) { return; return; } } $targetList = self::selectTargetList($entityType, $withPriority); $targetList = self::selectTargetList($entityType, $priority); Redis::saddarray($targetList, $entityIds); Redis::saddarray($targetList, $entityIds); } } * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Takes priority into consideration. * Takes priority into consideration. */ */ public static function getEntitiesSourceList(string $updateTarget, $priority = false): string public static function getEntitiesSourceList( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { return self::selectTargetList($updateTarget, $priority); return self::selectTargetList($updateTarget, $priority); } } /** /** * Externally called helper methods * Externally called helper methods * - count and flush * - count and flush */ */ public static function getEntitiesListCount(string $updateTarget, $priority = false): int public static function getEntitiesListCount( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): int { $targetList = self::selectTargetList($updateTarget, $priority); $targetList = self::selectTargetList($updateTarget, $priority); return Redis::scard($targetList); return Redis::scard($targetList); app/Component/ES/QueuePriorityEnum.php +40Lines changed: 40 additions & 0 deletions Original file line numberOriginal file lineDiff line numberDiff line change <?php declare(strict_types=1); namespace Jiminny\Component\ES; use Jiminny\Exceptions\InvalidArgumentException; enum QueuePriorityEnum: string { case HIGH = 'high'; case NORMAL = 'normal'; case LOW = 'low'; public static function tryFromString(string $value): self { if (! self::isValid($value)) { throw new InvalidArgumentException( sprintf('Invalid queue priority "%s" selected', $value) ); } return self::tryFrom($value); } public static function isValid(string $value): bool { return self::tryFrom($value) !== null; } public function isLow(): bool { return $this === self::LOW; } public function isHigh(): bool { return $this === self::HIGH; } } app/Component/ES/UpdateProcessManager.php +12-9Lines changed: 12 additions & 9 deletions Original file line numberOriginal file lineDiff line numberDiff line change if ($selectionList->isEmpty()) { if ($selectionList->isEmpty()) { return false; return false; } } /** /** * A stale chunk will always be smaller than a regular chunk. * A stale chunk will always be smaller than a regular chunk. * That doesn't mean there aren't any other scheduled entities for processing * That doesn't mean there aren't any other scheduled entities for processing private function rescheduleThrottledEntities(SelectionList $selectionList): void private function rescheduleThrottledEntities(SelectionList $selectionList): void { { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $groups = $selectionList->getEntityListGroups(); $this->updateTarget, foreach ($groups as $eachGroup) { $selectionList->getNormalPriorityEntityId() $groupEntityIds = $selectionList->getEntityListItemsByGroup($eachGroup); ); if (! empty($groupEntityIds)) { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $this->updateTarget, entityType: $this->updateTarget, $selectionList->getHighPriorityEntityIds(), entityIds: $groupEntityIds, true priority: QueuePriorityEnum::tryFromString($eachGroup) ); ); } } } } } } app/Console/Commands/Elasticsearch/AsyncUpdateEsEntities.php +9-3Lines changed: 9 additions & 3 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Illuminate\Support\Str; use Illuminate\Support\Str; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Component\ES\UpdateProcessManager; use Jiminny\Component\ES\UpdateProcessManager; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Traits\GracefullyStoppable; use Jiminny\Traits\GracefullyStoppable; Redis::set($gaugeLockName, true); Redis::set($gaugeLockName, true); Redis::expire($gaugeLockName, 60); Redis::expire($gaugeLockName, 60); $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::HIGH), ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update', $updateTarget), stat: sprintf('jiminny.%s-for-update', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::NORMAL), ); ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), stat: sprintf('jiminny.%s-for-update-low', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, true), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::LOW), ); ); } } app/Console/Commands/Elasticsearch/ResetAsyncElasticSearchCommand.php +5-1Lines changed: 5 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\Traits\ValidateUpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\ValidateUpdateTargetTrait; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Component\ES\Repositories\EsResetRepositoryInterface; use Jiminny\Component\ES\Repositories\EsResetRepositoryInterface; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Traits\GracefullyStoppable; use Jiminny\Traits\GracefullyStoppable; private function getRemainingScheduledEntities(bool $printStatus = false): int private function getRemainingScheduledEntities(bool $printStatus = false): int { { $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget, true); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount( $this->updateTarget, QueuePriorityEnum::HIGH ); if ($printStatus) { if ($printStatus) { $this->line( $this->line(
You said
app/Component/ES/Listeners/UpdateMultipleTargetsListener.php
+2-1Lines changed: 2 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\Component\ES\Listeners;
namespace Jiminny\Component\ES\Listeners;...
|
55699
|
NULL
|
NULL
|
NULL
|
|
55703
|
1935
|
4
|
2026-05-19T06:43:29.086388+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779173009086_m2.jpg...
|
Firefox
|
JY-20808 low priority indexing queue by Vasil-Jimi JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app — Work...
|
1
|
github.com/jiminny/app/pull/12082/changes#diff-616 github.com/jiminny/app/pull/12082/changes#diff-61654edeebd72388bddd97cafcac889a2d106f54bb484a719d4067878bb9b011...
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
Close tab
New Tab
Customize sidebar
Close Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
AI Chat settings
Close
WORK, Google Account: [EMAIL]
Main menu
New chat
Gemini
New Chat
Open menu for conversation actions.
Conversation with Gemini
Conversation with Gemini
Show the uploaded image in a lightbox
Copy prompt
You said Make a PR of changes Find potential issues and bottlenecks
You said
Make a PR of changes Find potential issues and bottlenecks
Listen
Show thinking
Gemini said
Gemini said
I can see you've uploaded a screenshot of a code diff, likely from a version control system given the red and green highlights. I would love to help you review the changes, spot bottlenecks, and help you draft a Pull Request.
However,
the image resolution is far too low for me to read.
It appears to be a completely zoomed-out view where the code has been reduced to tiny, illegible pixels. Because of this, I cannot extract any text or logic to analyze.
How You Can Share the Code
How You Can Share the Code
To help me review your code effectively, please try one of the following:
Paste the text directly:
Copy the specific code blocks (both the old and new versions if possible) and paste them directly into our chat.
Upload the files:
If the changes are extensive, you can upload the raw text or code files.
Take high-resolution screenshots:
If you must use images, take closer, readable screenshots of the specific functions or methods you want me to review.
Once you provide the readable code, I can dive right in to identify potential bugs, assess performance bottlenecks, and help you summarize the changes for your PR!
Good response
Bad response
Share & export
Copy
Show more options
Copy prompt
Edit
You said app/Component/ES/Listeners/UpdateMultipleTargetsListener.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\Component\ES\Listeners; namespace Jiminny\Component\ES\Listeners; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Contracts\ES\Events\UpdateMultipleEntities; use Jiminny\Contracts\ES\Events\UpdateMultipleEntities; use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface; AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntities(), $event->getEntities(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } } } app/Component/ES/Listeners/UpdateSingleTargetListener.php +9-1Lines changed: 9 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Actions\TrackElasticSearchOperations; use Jiminny\Component\ES\Actions\TrackElasticSearchOperations; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Contracts\ES\Events\UpdateSingleEntity; use Jiminny\Contracts\ES\Events\UpdateSingleEntity; use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface; 'entityId' => $event->getEntityId(), 'entityId' => $event->getEntityId(), ]); ]); /** * @important: * Synchronous event should eventually be deprecated. * Instant write operations are blocking and should be used sparingly. * It is much better in terms of performance to write 100 or 1000 documents at once, * and have one blocking reindex operation, instead of writing 10 documents synchronously. */ if ($event->isSyncEvent()) { if ($event->isSyncEvent()) { $this->handleSyncEvent($event); $this->handleSyncEvent($event); AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntityId(), $event->getEntityId(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } app/Component/ES/Processor/Actions/UpsertDocumentsAction.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SimpleCollection; use Jiminny\Component\ES\Processor\DTOs\SimpleCollection; use Jiminny\Component\ES\Processor\ResponseEvaluator; use Jiminny\Component\ES\Processor\ResponseEvaluator; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Exceptions\InvalidDataException; use Jiminny\Exceptions\InvalidDataException; use Sentry\Laravel\Facade as Sentry; use Sentry\Laravel\Facade as Sentry; AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( entityType: $this->updateTarget, entityType: $this->updateTarget, entityId: (int) $document->getId(), entityId: (int) $document->getId(), withPriority: true priority: QueuePriorityEnum::HIGH, ); ); } } app/Component/ES/Processor/DTOs/SelectionList.php +54-17Lines changed: 54 additions & 17 deletions Original file line numberOriginal file lineDiff line numberDiff line change namespace Jiminny\Component\ES\Processor\DTOs; namespace Jiminny\Component\ES\Processor\DTOs; use Jiminny\Component\ES\QueuePriorityEnum; /** /** * A very basic and simple collection of entity IDs. * A very basic and simple collection of entity IDs. */ */ class SelectionList class SelectionList { { public function __construct( private const int DEFAULT_CHUNK = 200; private readonly array $priorityEntityIdList = [], private readonly array $normalEntityIdList = [], private int $chunkSize = self::DEFAULT_CHUNK; private readonly bool $isStaleChunkSelected = false, private bool $isStaleChunkSelected = false; private readonly int $chunkSize = 200, private array $selectedEntityIds = []; ) { // Do nothing public function setChunkSize(int $chunkSize): void { $this->chunkSize = $chunkSize; } } public function getAllIds(): array public function markStale(): void { { return array_merge($this->priorityEntityIdList, $this->normalEntityIdList); $this->isStaleChunkSelected = true; } } public function count(): int public function addEntityList(string|QueuePriorityEnum $priority, array $entityIds): void { { return count($this->priorityEntityIdList) + count($this->normalEntityIdList); $priorityKey = $this->normalisePriority($priority); if (! array_key_exists($priorityKey, $this->selectedEntityIds)) { $this->selectedEntityIds[$priorityKey] = []; } $this->selectedEntityIds[$priorityKey] = array_merge($this->selectedEntityIds[$priorityKey], $entityIds); } } public function isEmpty(): bool /** * @return string[] */ public function getEntityListGroups(): array { { return empty($this->priorityEntityIdList) && empty($this->normalEntityIdList); return array_keys($this->selectedEntityIds); } } public function getHighPriorityEntityIds(): array public function getEntityListItemsByGroup(string|QueuePriorityEnum $priority): array { { return $this->priorityEntityIdList; $priorityKey = $this->normalisePriority($priority); return $this->selectedEntityIds[$priorityKey] ?? []; } } public function getNormalPriorityEntityId(): array public function getAllIds(): array { { return $this->normalEntityIdList; $allIds = []; foreach ($this->selectedEntityIds as $entityIds) { $allIds = array_merge($allIds, $entityIds); } return $allIds; } public function count(): int { return array_sum( array_map('count', $this->selectedEntityIds) ); } public function isEmpty(): bool { return $this->count() === 0; } } public function isStaleChunkSelected(): bool public function isStaleChunkSelected(): bool { { return $this->count() >= $this->chunkSize; return $this->count() >= $this->chunkSize; } } private function normalisePriority(string|QueuePriorityEnum $priority): string { return $priority instanceof QueuePriorityEnum ? $priority->value : $priority; } } } app/Component/ES/Processor/Traits/SelectEntityListTrait.php +27-4Lines changed: 27 additions & 4 deletions Original file line numberOriginal file lineDiff line numberDiff line change use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; /** /** * Build the correct source list name for the type of entity and priority * Build the correct source list name for the type of entity and priority */ */ trait SelectEntityListTrait trait SelectEntityListTrait { { /** * Highest priority queue for data requiring near-instant availability. * Very few entities should be added here, only when absolutely necessary. */ private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; /** * Normal priority queue for normal application operations. * Almost all update events should pass through this queue */ private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; protected static function selectTargetList(string $entityType, bool $withPriority = false): string /** { * Nonblocking low priority queue. This queue will be consumed only when there is nothing * with higher priority. * * This queue will be used for operations such as es:reset-async */ private const string ENTITIES_LOW_PRIORITIES_LIST = '%s-for-update-low'; protected static function selectTargetList( string $entityType, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { if (! in_array($entityType, UpdateTarget::allowedTargets())) { if (! in_array($entityType, UpdateTarget::allowedTargets())) { throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); } } if ($withPriority) { if ($priority->isHigh()) { Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); } } if ($priority->isLow()) { return sprintf(self::ENTITIES_LOW_PRIORITIES_LIST, $entityType); } return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); } } } } app/Component/ES/Processor/TargetEntitiesSelector.php +26-21Lines changed: 26 additions & 21 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SelectionList; use Jiminny\Component\ES\Processor\DTOs\SelectionList; use Jiminny\Component\ES\Processor\Traits\ExtractIdsTrait; use Jiminny\Component\ES\Processor\Traits\ExtractIdsTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\QueuePriorityEnum; /** /** * This class supplies a list of entities pending an update. * This class supplies a list of entities pending an update. public function select(): SelectionList public function select(): SelectionList { { $staleWorkEntityIds = $this->getStaleChunk(); $selectionList = new SelectionList(); $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $staleWorkEntityIds = $this->getStaleChunk(); if (count($staleWorkEntityIds) > 0) { if (count($staleWorkEntityIds) > 0) { return new SelectionList( /** priorityEntityIdList: $staleWorkEntityIds, * Stale chunks are treated as high priority isStaleChunkSelected: true, */ chunkSize: ChunkSize::getStaleChunkSize($this->updateTarget), $selectionList->markStale(); ); $selectionList->addEntityList(QueuePriorityEnum::HIGH, $staleWorkEntityIds); $selectionList->setChunkSize(ChunkSize::getStaleChunkSize($this->updateTarget)); return $selectionList; } } $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $selectionList->setChunkSize($mainChunkSize); $priorityEntityIdsList = $this->extractIdsFromSet( $priorityEntityIdsList = $this->extractIds(QueuePriorityEnum::HIGH, $mainChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, true), $selectionList->addEntityList(QueuePriorityEnum::HIGH, $priorityEntityIdsList); $mainChunkSize, ); $normalEntityIdsList = []; $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); if ($normalEntityChunkSize > 0) { if ($normalEntityChunkSize > 0) { $normalEntityIdsList = $this->extractIdsFromSet( $normalEntityIdsList = $this->extractIds(QueuePriorityEnum::NORMAL, $normalEntityChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, false), $selectionList->addEntityList(QueuePriorityEnum::NORMAL, $normalEntityIdsList); $normalEntityChunkSize ); } } return new SelectionList( return $selectionList; priorityEntityIdList: $priorityEntityIdsList, normalEntityIdList: $normalEntityIdsList, chunkSize: $mainChunkSize ); } } private function getStaleChunk(): array private function getStaleChunk(): array return []; return []; } } private function extractIds(QueuePriorityEnum $priority, int $chunkSize): array { return $this->extractIdsFromSet( AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, $priority), $chunkSize ); } } } app/Component/ES/AsyncUpdateElasticSearch.php +17-10Lines changed: 17 additions & 10 deletions Original file line numberOriginal file lineDiff line numberDiff line change * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * and other activity related data * and other activity related data */ */ public static function markEntityForUpdate(string $entityType, int $entityId, bool $withPriority = false): void public static function markEntityForUpdate( { string $entityType, $targetList = self::selectTargetList($entityType, $withPriority); int $entityId, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { $targetList = self::selectTargetList($entityType, $priority); Redis::sadd($targetList, $entityId); Redis::sadd($targetList, $entityId); Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ 'entityType' => $entityType, 'entityType' => $entityType, 'entityId' => $entityId, 'entityId' => $entityId, 'collectionKey' => $targetList, 'collectionKey' => $targetList, 'withPriority' => $withPriority, 'priority' => $priority->value, ]); ]); } } public static function bulkMarkEntitiesForUpdate( public static function bulkMarkEntitiesForUpdate( string $entityType, string $entityType, array $entityIds, array $entityIds, bool $withPriority = false QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { ): void { if (empty($entityIds)) { if (empty($entityIds)) { return; return; } } $targetList = self::selectTargetList($entityType, $withPriority); $targetList = self::selectTargetList($entityType, $priority); Redis::saddarray($targetList, $entityIds); Redis::saddarray($targetList, $entityIds); } } * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Takes priority into consideration. * Takes priority into consideration. */ */ public static function getEntitiesSourceList(string $updateTarget, $priority = false): string public static function getEntitiesSourceList( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { return self::selectTargetList($updateTarget, $priority); return self::selectTargetList($updateTarget, $priority); } } /** /** * Externally called helper methods * Externally called helper methods * - count and flush * - count and flush */ */ public static function getEntitiesListCount(string $updateTarget, $priority = false): int public static function getEntitiesListCount( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): int { $targetList = self::selectTargetList($updateTarget, $priority); $targetList = self::selectTargetList($updateTarget, $priority); return Redis::scard($targetList); return Redis::scard($targetList); app/Component/ES/QueuePriorityEnum.php +40Lines changed: 40 additions & 0 deletions Original file line numberOriginal file lineDiff line numberDiff line change <?php declare(strict_types=1); namespace Jiminny\Component\ES; use Jiminny\Exceptions\InvalidArgumentException; enum QueuePriorityEnum: string { case HIGH = 'high'; case NORMAL = 'normal'; case LOW = 'low'; public static function tryFromString(string $value): self { if (! self::isValid($value)) { throw new InvalidArgumentException( sprintf('Invalid queue priority "%s" selected', $value) ); } return self::tryFrom($value); } public static function isValid(string $value): bool { return self::tryFrom($value) !== null; } public function isLow(): bool { return $this === self::LOW; } public function isHigh(): bool { return $this === self::HIGH; } } app/Component/ES/UpdateProcessManager.php +12-9Lines changed: 12 additions & 9 deletions Original file line numberOriginal file lineDiff line numberDiff line change if ($selectionList->isEmpty()) { if ($selectionList->isEmpty()) { return false; return false; } } /** /** * A stale chunk will always be smaller than a regular chunk. * A stale chunk will always be smaller than a regular chunk. * That doesn't mean there aren't any other scheduled entities for processing * That doesn't mean there aren't any other scheduled entities for processing private function rescheduleThrottledEntities(SelectionList $selectionList): void private function rescheduleThrottledEntities(SelectionList $selectionList): void { { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $groups = $selectionList->getEntityListGroups(); $this->updateTarget, foreach ($groups as $eachGroup) { $selectionList->getNormalPriorityEntityId() $groupEntityIds = $selectionList->getEntityListItemsByGroup($eachGroup); ); if (! empty($groupEntityIds)) { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $this->updateTarget, entityType: $this->updateTarget, $selectionList->getHighPriorityEntityIds(), entityIds: $groupEntityIds, true priority: QueuePriorityEnum::tryFromString($eachGroup) ); ); } } } } } } app/Console/Commands/Elasticsearch/AsyncUpdateEsEntities.php +9-3Lines changed: 9 additions & 3 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Illuminate\Support\Str; use Illuminate\Support\Str; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Component\ES\UpdateProcessManager; use Jiminny\Component\ES\UpdateProcessManager; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Traits\GracefullyStoppable; use Jiminny\Traits\GracefullyStoppable; Redis::set($gaugeLockName, true); Redis::set($gaugeLockName, true); Redis::expire($gaugeLockName, 60); Redis::expire($gaugeLockName, 60); $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::HIGH), ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update', $updateTarget), stat: sprintf('jiminny.%s-for-update', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::NORMAL), ); ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), stat: sprintf('jiminny.%s-for-update-low', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, true), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::LOW), ); ); } } app/Console/Commands/Elasticsearch/ResetAsyncElasticSearchCommand.php +5-1Lines changed: 5 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\Traits\ValidateUpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\ValidateUpdateTargetTrait; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Component\ES\Repositories\EsResetRepositoryInterface; use Jiminny\Component\ES\Repositories\EsResetRepositoryInterface; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Traits\GracefullyStoppable; use Jiminny\Traits\GracefullyStoppable; private function getRemainingScheduledEntities(bool $printStatus = false): int private function getRemainingScheduledEntities(bool $printStatus = false): int { { $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget, true); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount( $this->updateTarget, QueuePriorityEnum::HIGH ); if ($printStatus) { if ($printStatus) { $this->line( $this->line(
You said
app/Component/ES/Listeners/UpdateMultipleTargetsListener.php
+2-1Lines changed: 2 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\Component\ES\Listeners;
namespace Jiminny\Component\ES\Listeners;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\QueuePriorityEnum;
use Jiminny\Contracts\ES\Events\UpdateMultipleEntities;
use Jiminny\Contracts\ES\Events\UpdateMultipleEntities;
use Psr\Log\LoggerInterface;
use Psr\Log\LoggerInterface;
AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(
AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(
$event->getUpdateTargetValue(),
$event->getUpdateTargetValue(),
$event->getEntities(),
$event->getEntities(),
$event->isPriority()
$event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL,
);
);
}
}
}
}
app/Component/ES/Listeners/UpdateSingleTargetListener.php
+9-1Lines changed: 9 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Actions\TrackElasticSearchOperations;
use Jiminny\Component\ES\Actions\TrackElasticSearchOperations;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\Processor\EntityQueryBuilder;
use Jiminny\Component\ES\Processor\EntityQueryBuilder;
use Jiminny\Component\ES\QueuePriorityEnum;
use Jiminny\Contracts\ES\Events\UpdateSingleEntity;
use Jiminny\Contracts\ES\Events\UpdateSingleEntity;
use Psr\Log\LoggerInterface;
use Psr\Log\LoggerInterface;
'entityId' => $event->getEntityId(),
'entityId' => $event->getEntityId(),
]);
]);
/**
* @important:
* Synchronous event should eventually be deprecated.
* Instant write operations are blocking and should be used sparingly.
* It is much better in terms of performance to write 100 or 1000 documents at once,
* and have one blocking reindex operation, instead of writing 10 documents synchronously.
*/
if ($event->isSyncEvent()) {
if ($event->isSyncEvent()) {
$this->handleSyncEvent($event);
$this->handleSyncEvent($event);
AsyncUpdateElasticSearch::markEntityForUpdate(
AsyncUpdateElasticSearch::markEntityForUpdate(
$event->getUpdateTargetValue(),
$event->getUpdateTargetValue(),
$event->getEntityId(),
$event->getEntityId(),
$event->isPriority()
$event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL,
);
);
}
}
app/Component/ES/Processor/Actions/UpsertDocumentsAction.php
+2-1Lines changed: 2 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SimpleCollection;
use Jiminny\Component\ES\Processor\DTOs\SimpleCollection;
use Jiminny\Component\ES\Processor\ResponseEvaluator;
use Jiminny\Component\ES\Processor\ResponseEvaluator;
use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait;
use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait;
use Jiminny\Component\ES\QueuePriorityEnum;
use Jiminny\Exceptions\InvalidDataException;
use Jiminny\Exceptions\InvalidDataException;
use Sentry\Laravel\Facade as Sentry;
use Sentry\Laravel\Facade as Sentry;
AsyncUpdateElasticSearch::markEntityForUpdate(
AsyncUpdateElasticSearch::markEntityForUpdate(
entityType: $this->updateTarget,
entityType: $this->updateTarget,
entityId: (int) $document->getId(),
entityId: (int) $document->getId(),
withPriority: true
priority: QueuePriorityEnum::HIGH,
);
);
}
}
app/Component/ES/Processor/DTOs/SelectionList.php
+54-17Lines changed: 54 additions & 17 deletions
Original file line numberOriginal file lineDiff line numberDiff line change
namespace Jiminny\Component\ES\Processor\DTOs;
namespace Jiminny\Component\ES\Processor\DTOs;
use Jiminny\Component\ES\QueuePriorityEnum;
/**
/**
* A very basic and simple collection of entity IDs.
* A very basic and simple collection of entity IDs.
*/
*/
class SelectionList
class SelectionList
{
{
public function __construct(
private const int DEFAULT_CHUNK = 200;
private readonly array $priorityEntityIdList = [],
private readonly array $normalEntityIdList = [],
private int $chunkSize = self::DEFAULT_CHUNK;
private readonly bool $isStaleChunkSelected = false,
private bool $isStaleChunkSelected = false;
private readonly int $chunkSize = 200,
private array $selectedEntityIds = [];
) {
// Do nothing
public function setChunkSize(int $chunkSize): void
{
$this->chunkSize = $chunkSize;
}
}
public function getAllIds(): array
public function markStale(): void
{
{
return array_merge($this->priorityEntityIdList, $this->normalEntityIdList);
$this->isStaleChunkSelected = true;
}
}
public function count(): int
public function addEntityList(string|QueuePriorityEnum $priority, array $entityIds): void
{
{
return count($this->priorityEntityIdList) + count($this->normalEntityIdList);
$priorityKey = $this->normalisePriority($priority);
if (! array_key_exists($priorityKey, $this->selectedEntityIds)) {
$this->selectedEntityIds[$priorityKey] = [];
}
$this->selectedEntityIds[$priorityKey] = array_merge($this->selectedEntityIds[$priorityKey], $entityIds);
}
}
public function isEmpty(): bool
/**
* @return string[]
*/
public function getEntityListGroups(): array
{
{
return empty($this->priorityEntityIdList) && empty($this->normalEntityIdList);
return array_keys($this->selectedEntityIds);
}
}
public function getHighPriorityEntityIds(): array
public function getEntityListItemsByGroup(string|QueuePriorityEnum $priority): array
{
{
return $this->priorityEntityIdList;
$priorityKey = $this->normalisePriority($priority);
return $this->selectedEntityIds[$priorityKey] ?? [];
}
}
public function getNormalPriorityEntityId(): array
public function getAllIds(): array
{
{
return $this->normalEntityIdList;
$allIds = [];
foreach ($this->selectedEntityIds as $entityIds) {
$allIds = array_merge($allIds, $entityIds);
}
return $allIds;
}
public function count(): int
{
return array_sum(
array_map('count', $this->selectedEntityIds)...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira","depth":4,"bounds":{"left":0.0,"top":0.0518755,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.06304868,"width":0.10106383,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app","depth":4,"bounds":{"left":0.0,"top":0.08459697,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app","depth":5,"bounds":{"left":0.013297873,"top":0.09577015,"width":0.18816489,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app","depth":4,"bounds":{"left":0.0,"top":0.11731844,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app","depth":5,"bounds":{"left":0.013297873,"top":0.12849163,"width":0.15674867,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.06732048,"top":0.1245012,"width":0.007978723,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New Tab","depth":4,"bounds":{"left":0.0028257978,"top":0.15163608,"width":0.07413564,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"bounds":{"left":0.0028257978,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Close Google Gemini (⌃X)","depth":6,"bounds":{"left":0.013796543,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Tabs from other devices","depth":6,"bounds":{"left":0.024933511,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"bounds":{"left":0.036070477,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"bounds":{"left":0.04720745,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"AI Chat settings","depth":7,"bounds":{"left":0.35854387,"top":0.055067837,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Close","depth":7,"bounds":{"left":0.37051198,"top":0.055067837,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"WORK, Google Account: lukas.kovalik@jiminny.com","depth":12,"bounds":{"left":0.3678524,"top":0.103751,"width":0.013297873,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Main menu","depth":12,"bounds":{"left":0.08494016,"top":0.103751,"width":0.013297873,"height":0.031923383},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New chat","depth":12,"bounds":{"left":0.09823803,"top":0.10454908,"width":0.028590426,"height":0.030327214},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Gemini","depth":15,"bounds":{"left":0.1008976,"top":0.10973663,"width":0.021941489,"height":0.020351157},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"New Chat","depth":12,"bounds":{"left":0.33992687,"top":0.103751,"width":0.013297873,"height":0.031923383},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Open menu for conversation actions.","depth":12,"bounds":{"left":0.35322472,"top":0.103751,"width":0.013297873,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXHeading","text":"Conversation with Gemini","depth":15,"bounds":{"left":0.079288565,"top":0.14764565,"width":0.0003324468,"height":0.0007980846},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Conversation with Gemini","depth":16,"bounds":{"left":0.079288565,"top":0.15003991,"width":0.1200133,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Show the uploaded image in a lightbox","depth":21,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy prompt","depth":21,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"You said Make a PR of changes Find potential issues and bottlenecks","depth":21,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"You said","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Make a PR of changes Find potential issues and bottlenecks","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Listen","depth":22,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Show thinking","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Gemini said","depth":20,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Gemini said","depth":21,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"I can see you've uploaded a screenshot of a code diff, likely from a version control system given the red and green highlights. I would love to help you review the changes, spot bottlenecks, and help you draft a Pull Request.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"However,","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"the image resolution is far too low for me to read.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"It appears to be a completely zoomed-out view where the code has been reduced to tiny, illegible pixels. Because of this, I cannot extract any text or logic to analyze.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"How You Can Share the Code","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"How You Can Share the Code","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"To help me review your code effectively, please try one of the following:","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Paste the text directly:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Copy the specific code blocks (both the old and new versions if possible) and paste them directly into our chat.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Upload the files:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"If the changes are extensive, you can upload the raw text or code files.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Take high-resolution screenshots:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"If you must use images, take closer, readable screenshots of the specific functions or methods you want me to review.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Once you provide the readable code, I can dive right in to identify potential bugs, assess performance bottlenecks, and help you summarize the changes for your PR!","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Good response","depth":22,"on_screen":false,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Bad response","depth":22,"on_screen":false,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Share & export","depth":21,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy","depth":22,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Show more options","depth":21,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy prompt","depth":21,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Edit","depth":21,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"You said app/Component/ES/Listeners/UpdateMultipleTargetsListener.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\\Component\\ES\\Listeners; namespace Jiminny\\Component\\ES\\Listeners; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Contracts\\ES\\Events\\UpdateMultipleEntities; use Jiminny\\Contracts\\ES\\Events\\UpdateMultipleEntities; use Psr\\Log\\LoggerInterface; use Psr\\Log\\LoggerInterface; AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntities(), $event->getEntities(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } } } app/Component/ES/Listeners/UpdateSingleTargetListener.php +9-1Lines changed: 9 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Actions\\TrackElasticSearchOperations; use Jiminny\\Component\\ES\\Actions\\TrackElasticSearchOperations; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder; use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Contracts\\ES\\Events\\UpdateSingleEntity; use Jiminny\\Contracts\\ES\\Events\\UpdateSingleEntity; use Psr\\Log\\LoggerInterface; use Psr\\Log\\LoggerInterface; 'entityId' => $event->getEntityId(), 'entityId' => $event->getEntityId(), ]); ]); /** * @important: * Synchronous event should eventually be deprecated. * Instant write operations are blocking and should be used sparingly. * It is much better in terms of performance to write 100 or 1000 documents at once, * and have one blocking reindex operation, instead of writing 10 documents synchronously. */ if ($event->isSyncEvent()) { if ($event->isSyncEvent()) { $this->handleSyncEvent($event); $this->handleSyncEvent($event); AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntityId(), $event->getEntityId(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } app/Component/ES/Processor/Actions/UpsertDocumentsAction.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Processor\\DTOs\\SimpleCollection; use Jiminny\\Component\\ES\\Processor\\DTOs\\SimpleCollection; use Jiminny\\Component\\ES\\Processor\\ResponseEvaluator; use Jiminny\\Component\\ES\\Processor\\ResponseEvaluator; use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait; use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Exceptions\\InvalidDataException; use Jiminny\\Exceptions\\InvalidDataException; use Sentry\\Laravel\\Facade as Sentry; use Sentry\\Laravel\\Facade as Sentry; AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( entityType: $this->updateTarget, entityType: $this->updateTarget, entityId: (int) $document->getId(), entityId: (int) $document->getId(), withPriority: true priority: QueuePriorityEnum::HIGH, ); ); } } app/Component/ES/Processor/DTOs/SelectionList.php +54-17Lines changed: 54 additions & 17 deletions Original file line numberOriginal file lineDiff line numberDiff line change namespace Jiminny\\Component\\ES\\Processor\\DTOs; namespace Jiminny\\Component\\ES\\Processor\\DTOs; use Jiminny\\Component\\ES\\QueuePriorityEnum; /** /** * A very basic and simple collection of entity IDs. * A very basic and simple collection of entity IDs. */ */ class SelectionList class SelectionList { { public function __construct( private const int DEFAULT_CHUNK = 200; private readonly array $priorityEntityIdList = [], private readonly array $normalEntityIdList = [], private int $chunkSize = self::DEFAULT_CHUNK; private readonly bool $isStaleChunkSelected = false, private bool $isStaleChunkSelected = false; private readonly int $chunkSize = 200, private array $selectedEntityIds = []; ) { // Do nothing public function setChunkSize(int $chunkSize): void { $this->chunkSize = $chunkSize; } } public function getAllIds(): array public function markStale(): void { { return array_merge($this->priorityEntityIdList, $this->normalEntityIdList); $this->isStaleChunkSelected = true; } } public function count(): int public function addEntityList(string|QueuePriorityEnum $priority, array $entityIds): void { { return count($this->priorityEntityIdList) + count($this->normalEntityIdList); $priorityKey = $this->normalisePriority($priority); if (! array_key_exists($priorityKey, $this->selectedEntityIds)) { $this->selectedEntityIds[$priorityKey] = []; } $this->selectedEntityIds[$priorityKey] = array_merge($this->selectedEntityIds[$priorityKey], $entityIds); } } public function isEmpty(): bool /** * @return string[] */ public function getEntityListGroups(): array { { return empty($this->priorityEntityIdList) && empty($this->normalEntityIdList); return array_keys($this->selectedEntityIds); } } public function getHighPriorityEntityIds(): array public function getEntityListItemsByGroup(string|QueuePriorityEnum $priority): array { { return $this->priorityEntityIdList; $priorityKey = $this->normalisePriority($priority); return $this->selectedEntityIds[$priorityKey] ?? []; } } public function getNormalPriorityEntityId(): array public function getAllIds(): array { { return $this->normalEntityIdList; $allIds = []; foreach ($this->selectedEntityIds as $entityIds) { $allIds = array_merge($allIds, $entityIds); } return $allIds; } public function count(): int { return array_sum( array_map('count', $this->selectedEntityIds) ); } public function isEmpty(): bool { return $this->count() === 0; } } public function isStaleChunkSelected(): bool public function isStaleChunkSelected(): bool { { return $this->count() >= $this->chunkSize; return $this->count() >= $this->chunkSize; } } private function normalisePriority(string|QueuePriorityEnum $priority): string { return $priority instanceof QueuePriorityEnum ? $priority->value : $priority; } } } app/Component/ES/Processor/Traits/SelectEntityListTrait.php +27-4Lines changed: 27 additions & 4 deletions Original file line numberOriginal file lineDiff line numberDiff line change use Illuminate\\Support\\Facades\\Log; use Illuminate\\Support\\Facades\\Log; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Exceptions\\InvalidArgumentException; use Jiminny\\Exceptions\\InvalidArgumentException; /** /** * Build the correct source list name for the type of entity and priority * Build the correct source list name for the type of entity and priority */ */ trait SelectEntityListTrait trait SelectEntityListTrait { { /** * Highest priority queue for data requiring near-instant availability. * Very few entities should be added here, only when absolutely necessary. */ private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; /** * Normal priority queue for normal application operations. * Almost all update events should pass through this queue */ private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; protected static function selectTargetList(string $entityType, bool $withPriority = false): string /** { * Nonblocking low priority queue. This queue will be consumed only when there is nothing * with higher priority. * * This queue will be used for operations such as es:reset-async */ private const string ENTITIES_LOW_PRIORITIES_LIST = '%s-for-update-low'; protected static function selectTargetList( string $entityType, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { if (! in_array($entityType, UpdateTarget::allowedTargets())) { if (! in_array($entityType, UpdateTarget::allowedTargets())) { throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); } } if ($withPriority) { if ($priority->isHigh()) { Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); } } if ($priority->isLow()) { return sprintf(self::ENTITIES_LOW_PRIORITIES_LIST, $entityType); } return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); } } } } app/Component/ES/Processor/TargetEntitiesSelector.php +26-21Lines changed: 26 additions & 21 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Processor\\DTOs\\SelectionList; use Jiminny\\Component\\ES\\Processor\\DTOs\\SelectionList; use Jiminny\\Component\\ES\\Processor\\Traits\\ExtractIdsTrait; use Jiminny\\Component\\ES\\Processor\\Traits\\ExtractIdsTrait; use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait; use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait; use Jiminny\\Component\\ES\\QueuePriorityEnum; /** /** * This class supplies a list of entities pending an update. * This class supplies a list of entities pending an update. public function select(): SelectionList public function select(): SelectionList { { $staleWorkEntityIds = $this->getStaleChunk(); $selectionList = new SelectionList(); $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $staleWorkEntityIds = $this->getStaleChunk(); if (count($staleWorkEntityIds) > 0) { if (count($staleWorkEntityIds) > 0) { return new SelectionList( /** priorityEntityIdList: $staleWorkEntityIds, * Stale chunks are treated as high priority isStaleChunkSelected: true, */ chunkSize: ChunkSize::getStaleChunkSize($this->updateTarget), $selectionList->markStale(); ); $selectionList->addEntityList(QueuePriorityEnum::HIGH, $staleWorkEntityIds); $selectionList->setChunkSize(ChunkSize::getStaleChunkSize($this->updateTarget)); return $selectionList; } } $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $selectionList->setChunkSize($mainChunkSize); $priorityEntityIdsList = $this->extractIdsFromSet( $priorityEntityIdsList = $this->extractIds(QueuePriorityEnum::HIGH, $mainChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, true), $selectionList->addEntityList(QueuePriorityEnum::HIGH, $priorityEntityIdsList); $mainChunkSize, ); $normalEntityIdsList = []; $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); if ($normalEntityChunkSize > 0) { if ($normalEntityChunkSize > 0) { $normalEntityIdsList = $this->extractIdsFromSet( $normalEntityIdsList = $this->extractIds(QueuePriorityEnum::NORMAL, $normalEntityChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, false), $selectionList->addEntityList(QueuePriorityEnum::NORMAL, $normalEntityIdsList); $normalEntityChunkSize ); } } return new SelectionList( return $selectionList; priorityEntityIdList: $priorityEntityIdsList, normalEntityIdList: $normalEntityIdsList, chunkSize: $mainChunkSize ); } } private function getStaleChunk(): array private function getStaleChunk(): array return []; return []; } } private function extractIds(QueuePriorityEnum $priority, int $chunkSize): array { return $this->extractIdsFromSet( AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, $priority), $chunkSize ); } } } app/Component/ES/AsyncUpdateElasticSearch.php +17-10Lines changed: 17 additions & 10 deletions Original file line numberOriginal file lineDiff line numberDiff line change * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * and other activity related data * and other activity related data */ */ public static function markEntityForUpdate(string $entityType, int $entityId, bool $withPriority = false): void public static function markEntityForUpdate( { string $entityType, $targetList = self::selectTargetList($entityType, $withPriority); int $entityId, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { $targetList = self::selectTargetList($entityType, $priority); Redis::sadd($targetList, $entityId); Redis::sadd($targetList, $entityId); Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ 'entityType' => $entityType, 'entityType' => $entityType, 'entityId' => $entityId, 'entityId' => $entityId, 'collectionKey' => $targetList, 'collectionKey' => $targetList, 'withPriority' => $withPriority, 'priority' => $priority->value, ]); ]); } } public static function bulkMarkEntitiesForUpdate( public static function bulkMarkEntitiesForUpdate( string $entityType, string $entityType, array $entityIds, array $entityIds, bool $withPriority = false QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { ): void { if (empty($entityIds)) { if (empty($entityIds)) { return; return; } } $targetList = self::selectTargetList($entityType, $withPriority); $targetList = self::selectTargetList($entityType, $priority); Redis::saddarray($targetList, $entityIds); Redis::saddarray($targetList, $entityIds); } } * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Takes priority into consideration. * Takes priority into consideration. */ */ public static function getEntitiesSourceList(string $updateTarget, $priority = false): string public static function getEntitiesSourceList( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { return self::selectTargetList($updateTarget, $priority); return self::selectTargetList($updateTarget, $priority); } } /** /** * Externally called helper methods * Externally called helper methods * - count and flush * - count and flush */ */ public static function getEntitiesListCount(string $updateTarget, $priority = false): int public static function getEntitiesListCount( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): int { $targetList = self::selectTargetList($updateTarget, $priority); $targetList = self::selectTargetList($updateTarget, $priority); return Redis::scard($targetList); return Redis::scard($targetList); app/Component/ES/QueuePriorityEnum.php +40Lines changed: 40 additions & 0 deletions Original file line numberOriginal file lineDiff line numberDiff line change <?php declare(strict_types=1); namespace Jiminny\\Component\\ES; use Jiminny\\Exceptions\\InvalidArgumentException; enum QueuePriorityEnum: string { case HIGH = 'high'; case NORMAL = 'normal'; case LOW = 'low'; public static function tryFromString(string $value): self { if (! self::isValid($value)) { throw new InvalidArgumentException( sprintf('Invalid queue priority \"%s\" selected', $value) ); } return self::tryFrom($value); } public static function isValid(string $value): bool { return self::tryFrom($value) !== null; } public function isLow(): bool { return $this === self::LOW; } public function isHigh(): bool { return $this === self::HIGH; } } app/Component/ES/UpdateProcessManager.php +12-9Lines changed: 12 additions & 9 deletions Original file line numberOriginal file lineDiff line numberDiff line change if ($selectionList->isEmpty()) { if ($selectionList->isEmpty()) { return false; return false; } } /** /** * A stale chunk will always be smaller than a regular chunk. * A stale chunk will always be smaller than a regular chunk. * That doesn't mean there aren't any other scheduled entities for processing * That doesn't mean there aren't any other scheduled entities for processing private function rescheduleThrottledEntities(SelectionList $selectionList): void private function rescheduleThrottledEntities(SelectionList $selectionList): void { { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $groups = $selectionList->getEntityListGroups(); $this->updateTarget, foreach ($groups as $eachGroup) { $selectionList->getNormalPriorityEntityId() $groupEntityIds = $selectionList->getEntityListItemsByGroup($eachGroup); ); if (! empty($groupEntityIds)) { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $this->updateTarget, entityType: $this->updateTarget, $selectionList->getHighPriorityEntityIds(), entityIds: $groupEntityIds, true priority: QueuePriorityEnum::tryFromString($eachGroup) ); ); } } } } } } app/Console/Commands/Elasticsearch/AsyncUpdateEsEntities.php +9-3Lines changed: 9 additions & 3 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Illuminate\\Support\\Str; use Illuminate\\Support\\Str; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Component\\ES\\UpdateProcessManager; use Jiminny\\Component\\ES\\UpdateProcessManager; use Jiminny\\Exceptions\\InvalidArgumentException; use Jiminny\\Exceptions\\InvalidArgumentException; use Jiminny\\Traits\\GracefullyStoppable; use Jiminny\\Traits\\GracefullyStoppable; Redis::set($gaugeLockName, true); Redis::set($gaugeLockName, true); Redis::expire($gaugeLockName, 60); Redis::expire($gaugeLockName, 60); $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::HIGH), ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update', $updateTarget), stat: sprintf('jiminny.%s-for-update', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::NORMAL), ); ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), stat: sprintf('jiminny.%s-for-update-low', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, true), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::LOW), ); ); } } app/Console/Commands/Elasticsearch/ResetAsyncElasticSearchCommand.php +5-1Lines changed: 5 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder; use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder; use Jiminny\\Component\\ES\\Processor\\Traits\\ValidateUpdateTargetTrait; use Jiminny\\Component\\ES\\Processor\\Traits\\ValidateUpdateTargetTrait; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Component\\ES\\Repositories\\EsResetRepositoryInterface; use Jiminny\\Component\\ES\\Repositories\\EsResetRepositoryInterface; use Jiminny\\Exceptions\\InvalidArgumentException; use Jiminny\\Exceptions\\InvalidArgumentException; use Jiminny\\Traits\\GracefullyStoppable; use Jiminny\\Traits\\GracefullyStoppable; private function getRemainingScheduledEntities(bool $printStatus = false): int private function getRemainingScheduledEntities(bool $printStatus = false): int { { $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget, true); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount( $this->updateTarget, QueuePriorityEnum::HIGH ); if ($printStatus) { if ($printStatus) { $this->line( $this->line(","depth":21,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"You said","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app/Component/ES/Listeners/UpdateMultipleTargetsListener.php","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"+2-1Lines changed: 2 additions & 1 deletion","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\\Component\\ES\\Listeners;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"namespace Jiminny\\Component\\ES\\Listeners;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\QueuePriorityEnum;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Contracts\\ES\\Events\\UpdateMultipleEntities;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Contracts\\ES\\Events\\UpdateMultipleEntities;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Psr\\Log\\LoggerInterface;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Psr\\Log\\LoggerInterface;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getUpdateTargetValue(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getUpdateTargetValue(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getEntities(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getEntities(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->isPriority()","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL,","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":");","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":");","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app/Component/ES/Listeners/UpdateSingleTargetListener.php","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"+9-1Lines changed: 9 additions & 1 deletion","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Actions\\TrackElasticSearchOperations;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Actions\\TrackElasticSearchOperations;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\QueuePriorityEnum;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Contracts\\ES\\Events\\UpdateSingleEntity;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Contracts\\ES\\Events\\UpdateSingleEntity;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Psr\\Log\\LoggerInterface;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Psr\\Log\\LoggerInterface;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"'entityId' => $event->getEntityId(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"'entityId' => $event->getEntityId(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"]);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"]);","depth":23,"bounds":{"left":0.20578457,"top":0.0,"width":0.0051529254,"height":0.016360734},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/**","depth":23,"bounds":{"left":0.20578457,"top":0.00518755,"width":0.0066489363,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* @important:","depth":23,"bounds":{"left":0.20578457,"top":0.06264964,"width":0.03374335,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* Synchronous event should eventually be deprecated.","depth":23,"bounds":{"left":0.20578457,"top":0.12011173,"width":0.13131648,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* Instant write operations are blocking and should be used sparingly.","depth":23,"bounds":{"left":0.20578457,"top":0.17757383,"width":0.12732713,"height":0.035514764},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* It is much better in terms of performance to write 100 or 1000 documents at once,","depth":23,"bounds":{"left":0.20578457,"top":0.25418994,"width":0.13314494,"height":0.035514764},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* and have one blocking reindex operation, instead of writing 10 documents synchronously.","depth":23,"bounds":{"left":0.20578457,"top":0.33080608,"width":0.12865691,"height":0.035514764},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"*/","depth":23,"bounds":{"left":0.20578457,"top":0.40742218,"width":0.004155585,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"if ($event->isSyncEvent()) {","depth":23,"bounds":{"left":0.20578457,"top":0.42657623,"width":0.065990694,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"if ($event->isSyncEvent()) {","depth":23,"bounds":{"left":0.20578457,"top":0.44573024,"width":0.065990694,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$this->handleSyncEvent($event);","depth":23,"bounds":{"left":0.20578457,"top":0.46488428,"width":0.08028591,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$this->handleSyncEvent($event);","depth":23,"bounds":{"left":0.20578457,"top":0.4840383,"width":0.08028591,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AsyncUpdateElasticSearch::markEntityForUpdate(","depth":23,"bounds":{"left":0.20578457,"top":0.5415004,"width":0.12117686,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AsyncUpdateElasticSearch::markEntityForUpdate(","depth":23,"bounds":{"left":0.20578457,"top":0.5606544,"width":0.12117686,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getUpdateTargetValue(),","depth":23,"bounds":{"left":0.20578457,"top":0.5798085,"width":0.0809508,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getUpdateTargetValue(),","depth":23,"bounds":{"left":0.20578457,"top":0.5989625,"width":0.0809508,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getEntityId(),","depth":23,"bounds":{"left":0.20578457,"top":0.6181165,"width":0.053025264,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getEntityId(),","depth":23,"bounds":{"left":0.20578457,"top":0.63727057,"width":0.053025264,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->isPriority()","depth":23,"bounds":{"left":0.20578457,"top":0.6564246,"width":0.046708778,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL,","depth":23,"bounds":{"left":0.20578457,"top":0.6755786,"width":0.11702128,"height":0.035514764},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":");","depth":23,"bounds":{"left":0.20578457,"top":0.7138867,"width":0.0033244682,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":");","depth":23,"bounds":{"left":0.20578457,"top":0.7330407,"width":0.0033244682,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"bounds":{"left":0.20578457,"top":0.75219476,"width":0.0019946808,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"bounds":{"left":0.20578457,"top":0.7713488,"width":0.0019946808,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app/Component/ES/Processor/Actions/UpsertDocumentsAction.php","depth":23,"bounds":{"left":0.20578457,"top":0.8288109,"width":0.09375,"height":0.035514764},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"+2-1Lines changed: 2 additions & 1 deletion","depth":23,"bounds":{"left":0.20578457,"top":0.88627297,"width":0.10388963,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Processor\\DTOs\\SimpleCollection;","depth":23,"bounds":{"left":0.20578457,"top":0.924581,"width":0.1356383,"height":0.073822826},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\DTOs\\SimpleCollection;","depth":23,"bounds":{"left":0.20578457,"top":1.0,"width":0.1356383,"height":-0.0011970997},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\ResponseEvaluator;","depth":23,"bounds":{"left":0.20578457,"top":1.0,"width":0.13115026,"height":-0.058659196},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\ResponseEvaluator;","depth":23,"bounds":{"left":0.20578457,"top":1.0,"width":0.13115026,"height":-0.09696722},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\QueuePriorityEnum;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Exceptions\\InvalidDataException;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Exceptions\\InvalidDataException;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Sentry\\Laravel\\Facade as Sentry;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Sentry\\Laravel\\Facade as Sentry;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AsyncUpdateElasticSearch::markEntityForUpdate(","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AsyncUpdateElasticSearch::markEntityForUpdate(","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"entityType: $this->updateTarget,","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"entityType: $this->updateTarget,","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"entityId: (int) $document->getId(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"entityId: (int) $document->getId(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"withPriority: true","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"priority: QueuePriorityEnum::HIGH,","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":");","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":");","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app/Component/ES/Processor/DTOs/SelectionList.php","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"+54-17Lines changed: 54 additions & 17 deletions","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Original file line numberOriginal file lineDiff line numberDiff line change","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"namespace Jiminny\\Component\\ES\\Processor\\DTOs;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"namespace Jiminny\\Component\\ES\\Processor\\DTOs;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\QueuePriorityEnum;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/**","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/**","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* A very basic and simple collection of entity IDs.","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* A very basic and simple collection of entity IDs.","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"*/","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"*/","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"class SelectionList","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"class SelectionList","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function __construct(","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private const int DEFAULT_CHUNK = 200;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private readonly array $priorityEntityIdList = [],","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private readonly array $normalEntityIdList = [],","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private int $chunkSize = self::DEFAULT_CHUNK;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private readonly bool $isStaleChunkSelected = false,","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private bool $isStaleChunkSelected = false;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private readonly int $chunkSize = 200,","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private array $selectedEntityIds = [];","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":") {","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"// Do nothing","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function setChunkSize(int $chunkSize): void","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$this->chunkSize = $chunkSize;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function getAllIds(): array","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function markStale(): void","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"return array_merge($this->priorityEntityIdList, $this->normalEntityIdList);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$this->isStaleChunkSelected = true;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function count(): int","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function addEntityList(string|QueuePriorityEnum $priority, array $entityIds): void","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"return count($this->priorityEntityIdList) + count($this->normalEntityIdList);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$priorityKey = $this->normalisePriority($priority);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"if (! array_key_exists($priorityKey, $this->selectedEntityIds)) {","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$this->selectedEntityIds[$priorityKey] = [];","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$this->selectedEntityIds[$priorityKey] = array_merge($this->selectedEntityIds[$priorityKey], $entityIds);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function isEmpty(): bool","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/**","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* @return string[]","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"*/","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function getEntityListGroups(): array","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"return empty($this->priorityEntityIdList) && empty($this->normalEntityIdList);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"return array_keys($this->selectedEntityIds);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function getHighPriorityEntityIds(): array","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function getEntityListItemsByGroup(string|QueuePriorityEnum $priority): array","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"return $this->priorityEntityIdList;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$priorityKey = $this->normalisePriority($priority);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"return $this->selectedEntityIds[$priorityKey] ?? [];","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function getNormalPriorityEntityId(): array","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function getAllIds(): array","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"return $this->normalEntityIdList;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$allIds = [];","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"foreach ($this->selectedEntityIds as $entityIds) {","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$allIds = array_merge($allIds, $entityIds);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"return $allIds;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function count(): int","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"return array_sum(","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"array_map('count', $this->selectedEntityIds)","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"}]...
|
-5187395540192962199
|
-1144453838252598132
|
click
|
accessibility
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
Close tab
New Tab
Customize sidebar
Close Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
AI Chat settings
Close
WORK, Google Account: [EMAIL]
Main menu
New chat
Gemini
New Chat
Open menu for conversation actions.
Conversation with Gemini
Conversation with Gemini
Show the uploaded image in a lightbox
Copy prompt
You said Make a PR of changes Find potential issues and bottlenecks
You said
Make a PR of changes Find potential issues and bottlenecks
Listen
Show thinking
Gemini said
Gemini said
I can see you've uploaded a screenshot of a code diff, likely from a version control system given the red and green highlights. I would love to help you review the changes, spot bottlenecks, and help you draft a Pull Request.
However,
the image resolution is far too low for me to read.
It appears to be a completely zoomed-out view where the code has been reduced to tiny, illegible pixels. Because of this, I cannot extract any text or logic to analyze.
How You Can Share the Code
How You Can Share the Code
To help me review your code effectively, please try one of the following:
Paste the text directly:
Copy the specific code blocks (both the old and new versions if possible) and paste them directly into our chat.
Upload the files:
If the changes are extensive, you can upload the raw text or code files.
Take high-resolution screenshots:
If you must use images, take closer, readable screenshots of the specific functions or methods you want me to review.
Once you provide the readable code, I can dive right in to identify potential bugs, assess performance bottlenecks, and help you summarize the changes for your PR!
Good response
Bad response
Share & export
Copy
Show more options
Copy prompt
Edit
You said app/Component/ES/Listeners/UpdateMultipleTargetsListener.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\Component\ES\Listeners; namespace Jiminny\Component\ES\Listeners; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Contracts\ES\Events\UpdateMultipleEntities; use Jiminny\Contracts\ES\Events\UpdateMultipleEntities; use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface; AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntities(), $event->getEntities(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } } } app/Component/ES/Listeners/UpdateSingleTargetListener.php +9-1Lines changed: 9 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Actions\TrackElasticSearchOperations; use Jiminny\Component\ES\Actions\TrackElasticSearchOperations; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Contracts\ES\Events\UpdateSingleEntity; use Jiminny\Contracts\ES\Events\UpdateSingleEntity; use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface; 'entityId' => $event->getEntityId(), 'entityId' => $event->getEntityId(), ]); ]); /** * @important: * Synchronous event should eventually be deprecated. * Instant write operations are blocking and should be used sparingly. * It is much better in terms of performance to write 100 or 1000 documents at once, * and have one blocking reindex operation, instead of writing 10 documents synchronously. */ if ($event->isSyncEvent()) { if ($event->isSyncEvent()) { $this->handleSyncEvent($event); $this->handleSyncEvent($event); AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntityId(), $event->getEntityId(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } app/Component/ES/Processor/Actions/UpsertDocumentsAction.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SimpleCollection; use Jiminny\Component\ES\Processor\DTOs\SimpleCollection; use Jiminny\Component\ES\Processor\ResponseEvaluator; use Jiminny\Component\ES\Processor\ResponseEvaluator; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Exceptions\InvalidDataException; use Jiminny\Exceptions\InvalidDataException; use Sentry\Laravel\Facade as Sentry; use Sentry\Laravel\Facade as Sentry; AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( entityType: $this->updateTarget, entityType: $this->updateTarget, entityId: (int) $document->getId(), entityId: (int) $document->getId(), withPriority: true priority: QueuePriorityEnum::HIGH, ); ); } } app/Component/ES/Processor/DTOs/SelectionList.php +54-17Lines changed: 54 additions & 17 deletions Original file line numberOriginal file lineDiff line numberDiff line change namespace Jiminny\Component\ES\Processor\DTOs; namespace Jiminny\Component\ES\Processor\DTOs; use Jiminny\Component\ES\QueuePriorityEnum; /** /** * A very basic and simple collection of entity IDs. * A very basic and simple collection of entity IDs. */ */ class SelectionList class SelectionList { { public function __construct( private const int DEFAULT_CHUNK = 200; private readonly array $priorityEntityIdList = [], private readonly array $normalEntityIdList = [], private int $chunkSize = self::DEFAULT_CHUNK; private readonly bool $isStaleChunkSelected = false, private bool $isStaleChunkSelected = false; private readonly int $chunkSize = 200, private array $selectedEntityIds = []; ) { // Do nothing public function setChunkSize(int $chunkSize): void { $this->chunkSize = $chunkSize; } } public function getAllIds(): array public function markStale(): void { { return array_merge($this->priorityEntityIdList, $this->normalEntityIdList); $this->isStaleChunkSelected = true; } } public function count(): int public function addEntityList(string|QueuePriorityEnum $priority, array $entityIds): void { { return count($this->priorityEntityIdList) + count($this->normalEntityIdList); $priorityKey = $this->normalisePriority($priority); if (! array_key_exists($priorityKey, $this->selectedEntityIds)) { $this->selectedEntityIds[$priorityKey] = []; } $this->selectedEntityIds[$priorityKey] = array_merge($this->selectedEntityIds[$priorityKey], $entityIds); } } public function isEmpty(): bool /** * @return string[] */ public function getEntityListGroups(): array { { return empty($this->priorityEntityIdList) && empty($this->normalEntityIdList); return array_keys($this->selectedEntityIds); } } public function getHighPriorityEntityIds(): array public function getEntityListItemsByGroup(string|QueuePriorityEnum $priority): array { { return $this->priorityEntityIdList; $priorityKey = $this->normalisePriority($priority); return $this->selectedEntityIds[$priorityKey] ?? []; } } public function getNormalPriorityEntityId(): array public function getAllIds(): array { { return $this->normalEntityIdList; $allIds = []; foreach ($this->selectedEntityIds as $entityIds) { $allIds = array_merge($allIds, $entityIds); } return $allIds; } public function count(): int { return array_sum( array_map('count', $this->selectedEntityIds) ); } public function isEmpty(): bool { return $this->count() === 0; } } public function isStaleChunkSelected(): bool public function isStaleChunkSelected(): bool { { return $this->count() >= $this->chunkSize; return $this->count() >= $this->chunkSize; } } private function normalisePriority(string|QueuePriorityEnum $priority): string { return $priority instanceof QueuePriorityEnum ? $priority->value : $priority; } } } app/Component/ES/Processor/Traits/SelectEntityListTrait.php +27-4Lines changed: 27 additions & 4 deletions Original file line numberOriginal file lineDiff line numberDiff line change use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; /** /** * Build the correct source list name for the type of entity and priority * Build the correct source list name for the type of entity and priority */ */ trait SelectEntityListTrait trait SelectEntityListTrait { { /** * Highest priority queue for data requiring near-instant availability. * Very few entities should be added here, only when absolutely necessary. */ private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; /** * Normal priority queue for normal application operations. * Almost all update events should pass through this queue */ private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; protected static function selectTargetList(string $entityType, bool $withPriority = false): string /** { * Nonblocking low priority queue. This queue will be consumed only when there is nothing * with higher priority. * * This queue will be used for operations such as es:reset-async */ private const string ENTITIES_LOW_PRIORITIES_LIST = '%s-for-update-low'; protected static function selectTargetList( string $entityType, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { if (! in_array($entityType, UpdateTarget::allowedTargets())) { if (! in_array($entityType, UpdateTarget::allowedTargets())) { throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); } } if ($withPriority) { if ($priority->isHigh()) { Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); } } if ($priority->isLow()) { return sprintf(self::ENTITIES_LOW_PRIORITIES_LIST, $entityType); } return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); } } } } app/Component/ES/Processor/TargetEntitiesSelector.php +26-21Lines changed: 26 additions & 21 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SelectionList; use Jiminny\Component\ES\Processor\DTOs\SelectionList; use Jiminny\Component\ES\Processor\Traits\ExtractIdsTrait; use Jiminny\Component\ES\Processor\Traits\ExtractIdsTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\QueuePriorityEnum; /** /** * This class supplies a list of entities pending an update. * This class supplies a list of entities pending an update. public function select(): SelectionList public function select(): SelectionList { { $staleWorkEntityIds = $this->getStaleChunk(); $selectionList = new SelectionList(); $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $staleWorkEntityIds = $this->getStaleChunk(); if (count($staleWorkEntityIds) > 0) { if (count($staleWorkEntityIds) > 0) { return new SelectionList( /** priorityEntityIdList: $staleWorkEntityIds, * Stale chunks are treated as high priority isStaleChunkSelected: true, */ chunkSize: ChunkSize::getStaleChunkSize($this->updateTarget), $selectionList->markStale(); ); $selectionList->addEntityList(QueuePriorityEnum::HIGH, $staleWorkEntityIds); $selectionList->setChunkSize(ChunkSize::getStaleChunkSize($this->updateTarget)); return $selectionList; } } $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $selectionList->setChunkSize($mainChunkSize); $priorityEntityIdsList = $this->extractIdsFromSet( $priorityEntityIdsList = $this->extractIds(QueuePriorityEnum::HIGH, $mainChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, true), $selectionList->addEntityList(QueuePriorityEnum::HIGH, $priorityEntityIdsList); $mainChunkSize, ); $normalEntityIdsList = []; $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); if ($normalEntityChunkSize > 0) { if ($normalEntityChunkSize > 0) { $normalEntityIdsList = $this->extractIdsFromSet( $normalEntityIdsList = $this->extractIds(QueuePriorityEnum::NORMAL, $normalEntityChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, false), $selectionList->addEntityList(QueuePriorityEnum::NORMAL, $normalEntityIdsList); $normalEntityChunkSize ); } } return new SelectionList( return $selectionList; priorityEntityIdList: $priorityEntityIdsList, normalEntityIdList: $normalEntityIdsList, chunkSize: $mainChunkSize ); } } private function getStaleChunk(): array private function getStaleChunk(): array return []; return []; } } private function extractIds(QueuePriorityEnum $priority, int $chunkSize): array { return $this->extractIdsFromSet( AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, $priority), $chunkSize ); } } } app/Component/ES/AsyncUpdateElasticSearch.php +17-10Lines changed: 17 additions & 10 deletions Original file line numberOriginal file lineDiff line numberDiff line change * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * and other activity related data * and other activity related data */ */ public static function markEntityForUpdate(string $entityType, int $entityId, bool $withPriority = false): void public static function markEntityForUpdate( { string $entityType, $targetList = self::selectTargetList($entityType, $withPriority); int $entityId, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { $targetList = self::selectTargetList($entityType, $priority); Redis::sadd($targetList, $entityId); Redis::sadd($targetList, $entityId); Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ 'entityType' => $entityType, 'entityType' => $entityType, 'entityId' => $entityId, 'entityId' => $entityId, 'collectionKey' => $targetList, 'collectionKey' => $targetList, 'withPriority' => $withPriority, 'priority' => $priority->value, ]); ]); } } public static function bulkMarkEntitiesForUpdate( public static function bulkMarkEntitiesForUpdate( string $entityType, string $entityType, array $entityIds, array $entityIds, bool $withPriority = false QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { ): void { if (empty($entityIds)) { if (empty($entityIds)) { return; return; } } $targetList = self::selectTargetList($entityType, $withPriority); $targetList = self::selectTargetList($entityType, $priority); Redis::saddarray($targetList, $entityIds); Redis::saddarray($targetList, $entityIds); } } * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Takes priority into consideration. * Takes priority into consideration. */ */ public static function getEntitiesSourceList(string $updateTarget, $priority = false): string public static function getEntitiesSourceList( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { return self::selectTargetList($updateTarget, $priority); return self::selectTargetList($updateTarget, $priority); } } /** /** * Externally called helper methods * Externally called helper methods * - count and flush * - count and flush */ */ public static function getEntitiesListCount(string $updateTarget, $priority = false): int public static function getEntitiesListCount( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): int { $targetList = self::selectTargetList($updateTarget, $priority); $targetList = self::selectTargetList($updateTarget, $priority); return Redis::scard($targetList); return Redis::scard($targetList); app/Component/ES/QueuePriorityEnum.php +40Lines changed: 40 additions & 0 deletions Original file line numberOriginal file lineDiff line numberDiff line change <?php declare(strict_types=1); namespace Jiminny\Component\ES; use Jiminny\Exceptions\InvalidArgumentException; enum QueuePriorityEnum: string { case HIGH = 'high'; case NORMAL = 'normal'; case LOW = 'low'; public static function tryFromString(string $value): self { if (! self::isValid($value)) { throw new InvalidArgumentException( sprintf('Invalid queue priority "%s" selected', $value) ); } return self::tryFrom($value); } public static function isValid(string $value): bool { return self::tryFrom($value) !== null; } public function isLow(): bool { return $this === self::LOW; } public function isHigh(): bool { return $this === self::HIGH; } } app/Component/ES/UpdateProcessManager.php +12-9Lines changed: 12 additions & 9 deletions Original file line numberOriginal file lineDiff line numberDiff line change if ($selectionList->isEmpty()) { if ($selectionList->isEmpty()) { return false; return false; } } /** /** * A stale chunk will always be smaller than a regular chunk. * A stale chunk will always be smaller than a regular chunk. * That doesn't mean there aren't any other scheduled entities for processing * That doesn't mean there aren't any other scheduled entities for processing private function rescheduleThrottledEntities(SelectionList $selectionList): void private function rescheduleThrottledEntities(SelectionList $selectionList): void { { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $groups = $selectionList->getEntityListGroups(); $this->updateTarget, foreach ($groups as $eachGroup) { $selectionList->getNormalPriorityEntityId() $groupEntityIds = $selectionList->getEntityListItemsByGroup($eachGroup); ); if (! empty($groupEntityIds)) { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $this->updateTarget, entityType: $this->updateTarget, $selectionList->getHighPriorityEntityIds(), entityIds: $groupEntityIds, true priority: QueuePriorityEnum::tryFromString($eachGroup) ); ); } } } } } } app/Console/Commands/Elasticsearch/AsyncUpdateEsEntities.php +9-3Lines changed: 9 additions & 3 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Illuminate\Support\Str; use Illuminate\Support\Str; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Component\ES\UpdateProcessManager; use Jiminny\Component\ES\UpdateProcessManager; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Traits\GracefullyStoppable; use Jiminny\Traits\GracefullyStoppable; Redis::set($gaugeLockName, true); Redis::set($gaugeLockName, true); Redis::expire($gaugeLockName, 60); Redis::expire($gaugeLockName, 60); $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::HIGH), ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update', $updateTarget), stat: sprintf('jiminny.%s-for-update', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::NORMAL), ); ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), stat: sprintf('jiminny.%s-for-update-low', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, true), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::LOW), ); ); } } app/Console/Commands/Elasticsearch/ResetAsyncElasticSearchCommand.php +5-1Lines changed: 5 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\Traits\ValidateUpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\ValidateUpdateTargetTrait; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Component\ES\Repositories\EsResetRepositoryInterface; use Jiminny\Component\ES\Repositories\EsResetRepositoryInterface; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Traits\GracefullyStoppable; use Jiminny\Traits\GracefullyStoppable; private function getRemainingScheduledEntities(bool $printStatus = false): int private function getRemainingScheduledEntities(bool $printStatus = false): int { { $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget, true); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount( $this->updateTarget, QueuePriorityEnum::HIGH ); if ($printStatus) { if ($printStatus) { $this->line( $this->line(
You said
app/Component/ES/Listeners/UpdateMultipleTargetsListener.php
+2-1Lines changed: 2 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\Component\ES\Listeners;
namespace Jiminny\Component\ES\Listeners;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\QueuePriorityEnum;
use Jiminny\Contracts\ES\Events\UpdateMultipleEntities;
use Jiminny\Contracts\ES\Events\UpdateMultipleEntities;
use Psr\Log\LoggerInterface;
use Psr\Log\LoggerInterface;
AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(
AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(
$event->getUpdateTargetValue(),
$event->getUpdateTargetValue(),
$event->getEntities(),
$event->getEntities(),
$event->isPriority()
$event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL,
);
);
}
}
}
}
app/Component/ES/Listeners/UpdateSingleTargetListener.php
+9-1Lines changed: 9 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Actions\TrackElasticSearchOperations;
use Jiminny\Component\ES\Actions\TrackElasticSearchOperations;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\Processor\EntityQueryBuilder;
use Jiminny\Component\ES\Processor\EntityQueryBuilder;
use Jiminny\Component\ES\QueuePriorityEnum;
use Jiminny\Contracts\ES\Events\UpdateSingleEntity;
use Jiminny\Contracts\ES\Events\UpdateSingleEntity;
use Psr\Log\LoggerInterface;
use Psr\Log\LoggerInterface;
'entityId' => $event->getEntityId(),
'entityId' => $event->getEntityId(),
]);
]);
/**
* @important:
* Synchronous event should eventually be deprecated.
* Instant write operations are blocking and should be used sparingly.
* It is much better in terms of performance to write 100 or 1000 documents at once,
* and have one blocking reindex operation, instead of writing 10 documents synchronously.
*/
if ($event->isSyncEvent()) {
if ($event->isSyncEvent()) {
$this->handleSyncEvent($event);
$this->handleSyncEvent($event);
AsyncUpdateElasticSearch::markEntityForUpdate(
AsyncUpdateElasticSearch::markEntityForUpdate(
$event->getUpdateTargetValue(),
$event->getUpdateTargetValue(),
$event->getEntityId(),
$event->getEntityId(),
$event->isPriority()
$event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL,
);
);
}
}
app/Component/ES/Processor/Actions/UpsertDocumentsAction.php
+2-1Lines changed: 2 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SimpleCollection;
use Jiminny\Component\ES\Processor\DTOs\SimpleCollection;
use Jiminny\Component\ES\Processor\ResponseEvaluator;
use Jiminny\Component\ES\Processor\ResponseEvaluator;
use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait;
use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait;
use Jiminny\Component\ES\QueuePriorityEnum;
use Jiminny\Exceptions\InvalidDataException;
use Jiminny\Exceptions\InvalidDataException;
use Sentry\Laravel\Facade as Sentry;
use Sentry\Laravel\Facade as Sentry;
AsyncUpdateElasticSearch::markEntityForUpdate(
AsyncUpdateElasticSearch::markEntityForUpdate(
entityType: $this->updateTarget,
entityType: $this->updateTarget,
entityId: (int) $document->getId(),
entityId: (int) $document->getId(),
withPriority: true
priority: QueuePriorityEnum::HIGH,
);
);
}
}
app/Component/ES/Processor/DTOs/SelectionList.php
+54-17Lines changed: 54 additions & 17 deletions
Original file line numberOriginal file lineDiff line numberDiff line change
namespace Jiminny\Component\ES\Processor\DTOs;
namespace Jiminny\Component\ES\Processor\DTOs;
use Jiminny\Component\ES\QueuePriorityEnum;
/**
/**
* A very basic and simple collection of entity IDs.
* A very basic and simple collection of entity IDs.
*/
*/
class SelectionList
class SelectionList
{
{
public function __construct(
private const int DEFAULT_CHUNK = 200;
private readonly array $priorityEntityIdList = [],
private readonly array $normalEntityIdList = [],
private int $chunkSize = self::DEFAULT_CHUNK;
private readonly bool $isStaleChunkSelected = false,
private bool $isStaleChunkSelected = false;
private readonly int $chunkSize = 200,
private array $selectedEntityIds = [];
) {
// Do nothing
public function setChunkSize(int $chunkSize): void
{
$this->chunkSize = $chunkSize;
}
}
public function getAllIds(): array
public function markStale(): void
{
{
return array_merge($this->priorityEntityIdList, $this->normalEntityIdList);
$this->isStaleChunkSelected = true;
}
}
public function count(): int
public function addEntityList(string|QueuePriorityEnum $priority, array $entityIds): void
{
{
return count($this->priorityEntityIdList) + count($this->normalEntityIdList);
$priorityKey = $this->normalisePriority($priority);
if (! array_key_exists($priorityKey, $this->selectedEntityIds)) {
$this->selectedEntityIds[$priorityKey] = [];
}
$this->selectedEntityIds[$priorityKey] = array_merge($this->selectedEntityIds[$priorityKey], $entityIds);
}
}
public function isEmpty(): bool
/**
* @return string[]
*/
public function getEntityListGroups(): array
{
{
return empty($this->priorityEntityIdList) && empty($this->normalEntityIdList);
return array_keys($this->selectedEntityIds);
}
}
public function getHighPriorityEntityIds(): array
public function getEntityListItemsByGroup(string|QueuePriorityEnum $priority): array
{
{
return $this->priorityEntityIdList;
$priorityKey = $this->normalisePriority($priority);
return $this->selectedEntityIds[$priorityKey] ?? [];
}
}
public function getNormalPriorityEntityId(): array
public function getAllIds(): array
{
{
return $this->normalEntityIdList;
$allIds = [];
foreach ($this->selectedEntityIds as $entityIds) {
$allIds = array_merge($allIds, $entityIds);
}
return $allIds;
}
public function count(): int
{
return array_sum(
array_map('count', $this->selectedEntityIds)...
|
55701
|
NULL
|
NULL
|
NULL
|
|
55704
|
1935
|
5
|
2026-05-19T06:43:38.063680+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779173018063_m2.jpg...
|
Firefox
|
JY-20808 low priority indexing queue by Vasil-Jimi JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app — Work...
|
1
|
github.com/jiminny/app/pull/12082/changes#diff-616 github.com/jiminny/app/pull/12082/changes#diff-61654edeebd72388bddd97cafcac889a2d106f54bb484a719d4067878bb9b011...
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
Close tab
New Tab
Customize sidebar
Close Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
AI Chat settings
Close
WORK, Google Account: [EMAIL]
Main menu
New chat
Gemini
New Chat
Open menu for conversation actions.
Conversation with Gemini
Conversation with Gemini
Show the uploaded image in a lightbox
Copy prompt
You said Make a PR of changes Find potential issues and bottlenecks
You said
Make a PR of changes Find potential issues and bottlenecks
Listen
Show thinking
Gemini said
Gemini said
I can see you've uploaded a screenshot of a code diff, likely from a version control system given the red and green highlights. I would love to help you review the changes, spot bottlenecks, and help you draft a Pull Request.
However,
the image resolution is far too low for me to read.
It appears to be a completely zoomed-out view where the code has been reduced to tiny, illegible pixels. Because of this, I cannot extract any text or logic to analyze.
How You Can Share the Code
How You Can Share the Code
To help me review your code effectively, please try one of the following:
Paste the text directly:
Copy the specific code blocks (both the old and new versions if possible) and paste them directly into our chat.
Upload the files:
If the changes are extensive, you can upload the raw text or code files.
Take high-resolution screenshots:
If you must use images, take closer, readable screenshots of the specific functions or methods you want me to review.
Once you provide the readable code, I can dive right in to identify potential bugs, assess performance bottlenecks, and help you summarize the changes for your PR!
Good response
Bad response
Share & export
Copy
Show more options
Copy prompt
Edit
You said app/Component/ES/Listeners/UpdateMultipleTargetsListener.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\Component\ES\Listeners; namespace Jiminny\Component\ES\Listeners; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Contracts\ES\Events\UpdateMultipleEntities; use Jiminny\Contracts\ES\Events\UpdateMultipleEntities; use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface; AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntities(), $event->getEntities(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } } } app/Component/ES/Listeners/UpdateSingleTargetListener.php +9-1Lines changed: 9 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Actions\TrackElasticSearchOperations; use Jiminny\Component\ES\Actions\TrackElasticSearchOperations; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Contracts\ES\Events\UpdateSingleEntity; use Jiminny\Contracts\ES\Events\UpdateSingleEntity; use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface; 'entityId' => $event->getEntityId(), 'entityId' => $event->getEntityId(), ]); ]); /** * @important: * Synchronous event should eventually be deprecated. * Instant write operations are blocking and should be used sparingly. * It is much better in terms of performance to write 100 or 1000 documents at once, * and have one blocking reindex operation, instead of writing 10 documents synchronously. */ if ($event->isSyncEvent()) { if ($event->isSyncEvent()) { $this->handleSyncEvent($event); $this->handleSyncEvent($event); AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntityId(), $event->getEntityId(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } app/Component/ES/Processor/Actions/UpsertDocumentsAction.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SimpleCollection; use Jiminny\Component\ES\Processor\DTOs\SimpleCollection; use Jiminny\Component\ES\Processor\ResponseEvaluator; use Jiminny\Component\ES\Processor\ResponseEvaluator; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Exceptions\InvalidDataException; use Jiminny\Exceptions\InvalidDataException; use Sentry\Laravel\Facade as Sentry; use Sentry\Laravel\Facade as Sentry; AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( entityType: $this->updateTarget, entityType: $this->updateTarget, entityId: (int) $document->getId(), entityId: (int) $document->getId(), withPriority: true priority: QueuePriorityEnum::HIGH, ); ); } } app/Component/ES/Processor/DTOs/SelectionList.php +54-17Lines changed: 54 additions & 17 deletions Original file line numberOriginal file lineDiff line numberDiff line change namespace Jiminny\Component\ES\Processor\DTOs; namespace Jiminny\Component\ES\Processor\DTOs; use Jiminny\Component\ES\QueuePriorityEnum; /** /** * A very basic and simple collection of entity IDs. * A very basic and simple collection of entity IDs. */ */ class SelectionList class SelectionList { { public function __construct( private const int DEFAULT_CHUNK = 200; private readonly array $priorityEntityIdList = [], private readonly array $normalEntityIdList = [], private int $chunkSize = self::DEFAULT_CHUNK; private readonly bool $isStaleChunkSelected = false, private bool $isStaleChunkSelected = false; private readonly int $chunkSize = 200, private array $selectedEntityIds = []; ) { // Do nothing public function setChunkSize(int $chunkSize): void { $this->chunkSize = $chunkSize; } } public function getAllIds(): array public function markStale(): void { { return array_merge($this->priorityEntityIdList, $this->normalEntityIdList); $this->isStaleChunkSelected = true; } } public function count(): int public function addEntityList(string|QueuePriorityEnum $priority, array $entityIds): void { { return count($this->priorityEntityIdList) + count($this->normalEntityIdList); $priorityKey = $this->normalisePriority($priority); if (! array_key_exists($priorityKey, $this->selectedEntityIds)) { $this->selectedEntityIds[$priorityKey] = []; } $this->selectedEntityIds[$priorityKey] = array_merge($this->selectedEntityIds[$priorityKey], $entityIds); } } public function isEmpty(): bool /** * @return string[] */ public function getEntityListGroups(): array { { return empty($this->priorityEntityIdList) && empty($this->normalEntityIdList); return array_keys($this->selectedEntityIds); } } public function getHighPriorityEntityIds(): array public function getEntityListItemsByGroup(string|QueuePriorityEnum $priority): array { { return $this->priorityEntityIdList; $priorityKey = $this->normalisePriority($priority); return $this->selectedEntityIds[$priorityKey] ?? []; } } public function getNormalPriorityEntityId(): array public function getAllIds(): array { { return $this->normalEntityIdList; $allIds = []; foreach ($this->selectedEntityIds as $entityIds) { $allIds = array_merge($allIds, $entityIds); } return $allIds; } public function count(): int { return array_sum( array_map('count', $this->selectedEntityIds) ); } public function isEmpty(): bool { return $this->count() === 0; } } public function isStaleChunkSelected(): bool public function isStaleChunkSelected(): bool { { return $this->count() >= $this->chunkSize; return $this->count() >= $this->chunkSize; } } private function normalisePriority(string|QueuePriorityEnum $priority): string { return $priority instanceof QueuePriorityEnum ? $priority->value : $priority; } } } app/Component/ES/Processor/Traits/SelectEntityListTrait.php +27-4Lines changed: 27 additions & 4 deletions Original file line numberOriginal file lineDiff line numberDiff line change use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; /** /** * Build the correct source list name for the type of entity and priority * Build the correct source list name for the type of entity and priority */ */ trait SelectEntityListTrait trait SelectEntityListTrait { { /** * Highest priority queue for data requiring near-instant availability. * Very few entities should be added here, only when absolutely necessary. */ private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; /** * Normal priority queue for normal application operations. * Almost all update events should pass through this queue */ private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; protected static function selectTargetList(string $entityType, bool $withPriority = false): string /** { * Nonblocking low priority queue. This queue will be consumed only when there is nothing * with higher priority. * * This queue will be used for operations such as es:reset-async */ private const string ENTITIES_LOW_PRIORITIES_LIST = '%s-for-update-low'; protected static function selectTargetList( string $entityType, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { if (! in_array($entityType, UpdateTarget::allowedTargets())) { if (! in_array($entityType, UpdateTarget::allowedTargets())) { throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); } } if ($withPriority) { if ($priority->isHigh()) { Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); } } if ($priority->isLow()) { return sprintf(self::ENTITIES_LOW_PRIORITIES_LIST, $entityType); } return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); } } } } app/Component/ES/Processor/TargetEntitiesSelector.php +26-21Lines changed: 26 additions & 21 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SelectionList; use Jiminny\Component\ES\Processor\DTOs\SelectionList; use Jiminny\Component\ES\Processor\Traits\ExtractIdsTrait; use Jiminny\Component\ES\Processor\Traits\ExtractIdsTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\QueuePriorityEnum; /** /** * This class supplies a list of entities pending an update. * This class supplies a list of entities pending an update. public function select(): SelectionList public function select(): SelectionList { { $staleWorkEntityIds = $this->getStaleChunk(); $selectionList = new SelectionList(); $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $staleWorkEntityIds = $this->getStaleChunk(); if (count($staleWorkEntityIds) > 0) { if (count($staleWorkEntityIds) > 0) { return new SelectionList( /** priorityEntityIdList: $staleWorkEntityIds, * Stale chunks are treated as high priority isStaleChunkSelected: true, */ chunkSize: ChunkSize::getStaleChunkSize($this->updateTarget), $selectionList->markStale(); ); $selectionList->addEntityList(QueuePriorityEnum::HIGH, $staleWorkEntityIds); $selectionList->setChunkSize(ChunkSize::getStaleChunkSize($this->updateTarget)); return $selectionList; } } $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $selectionList->setChunkSize($mainChunkSize); $priorityEntityIdsList = $this->extractIdsFromSet( $priorityEntityIdsList = $this->extractIds(QueuePriorityEnum::HIGH, $mainChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, true), $selectionList->addEntityList(QueuePriorityEnum::HIGH, $priorityEntityIdsList); $mainChunkSize, ); $normalEntityIdsList = []; $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); if ($normalEntityChunkSize > 0) { if ($normalEntityChunkSize > 0) { $normalEntityIdsList = $this->extractIdsFromSet( $normalEntityIdsList = $this->extractIds(QueuePriorityEnum::NORMAL, $normalEntityChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, false), $selectionList->addEntityList(QueuePriorityEnum::NORMAL, $normalEntityIdsList); $normalEntityChunkSize ); } } return new SelectionList( return $selectionList; priorityEntityIdList: $priorityEntityIdsList, normalEntityIdList: $normalEntityIdsList, chunkSize: $mainChunkSize ); } } private function getStaleChunk(): array private function getStaleChunk(): array return []; return []; } } private function extractIds(QueuePriorityEnum $priority, int $chunkSize): array { return $this->extractIdsFromSet( AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, $priority), $chunkSize ); } } } app/Component/ES/AsyncUpdateElasticSearch.php +17-10Lines changed: 17 additions & 10 deletions Original file line numberOriginal file lineDiff line numberDiff line change * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * and other activity related data * and other activity related data */ */ public static function markEntityForUpdate(string $entityType, int $entityId, bool $withPriority = false): void public static function markEntityForUpdate( { string $entityType, $targetList = self::selectTargetList($entityType, $withPriority); int $entityId, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { $targetList = self::selectTargetList($entityType, $priority); Redis::sadd($targetList, $entityId); Redis::sadd($targetList, $entityId); Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ 'entityType' => $entityType, 'entityType' => $entityType, 'entityId' => $entityId, 'entityId' => $entityId, 'collectionKey' => $targetList, 'collectionKey' => $targetList, 'withPriority' => $withPriority, 'priority' => $priority->value, ]); ]); } } public static function bulkMarkEntitiesForUpdate( public static function bulkMarkEntitiesForUpdate( string $entityType, string $entityType, array $entityIds, array $entityIds, bool $withPriority = false QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { ): void { if (empty($entityIds)) { if (empty($entityIds)) { return; return; } } $targetList = self::selectTargetList($entityType, $withPriority); $targetList = self::selectTargetList($entityType, $priority); Redis::saddarray($targetList, $entityIds); Redis::saddarray($targetList, $entityIds); } } * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Takes priority into consideration. * Takes priority into consideration. */ */ public static function getEntitiesSourceList(string $updateTarget, $priority = false): string public static function getEntitiesSourceList( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { return self::selectTargetList($updateTarget, $priority); return self::selectTargetList($updateTarget, $priority); } } /** /** * Externally called helper methods * Externally called helper methods * - count and flush * - count and flush */ */ public static function getEntitiesListCount(string $updateTarget, $priority = false): int public static function getEntitiesListCount( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): int { $targetList = self::selectTargetList($updateTarget, $priority); $targetList = self::selectTargetList($updateTarget, $priority); return Redis::scard($targetList); return Redis::scard($targetList); app/Component/ES/QueuePriorityEnum.php +40Lines changed: 40 additions & 0 deletions Original file line numberOriginal file lineDiff line numberDiff line change <?php declare(strict_types=1); namespace Jiminny\Component\ES; use Jiminny\Exceptions\InvalidArgumentException; enum QueuePriorityEnum: string { case HIGH = 'high'; case NORMAL = 'normal'; case LOW = 'low'; public static function tryFromString(string $value): self { if (! self::isValid($value)) { throw new InvalidArgumentException( sprintf('Invalid queue priority "%s" selected', $value) ); } return self::tryFrom($value); } public static function isValid(string $value): bool { return self::tryFrom($value) !== null; } public function isLow(): bool { return $this === self::LOW; } public function isHigh(): bool { return $this === self::HIGH; } } app/Component/ES/UpdateProcessManager.php +12-9Lines changed: 12 additions & 9 deletions Original file line numberOriginal file lineDiff line numberDiff line change if ($selectionList->isEmpty()) { if ($selectionList->isEmpty()) { return false; return false; } } /** /** * A stale chunk will always be smaller than a regular chunk. * A stale chunk will always be smaller than a regular chunk. * That doesn't mean there aren't any other scheduled entities for processing * That doesn't mean there aren't any other scheduled entities for processing private function rescheduleThrottledEntities(SelectionList $selectionList): void private function rescheduleThrottledEntities(SelectionList $selectionList): void { { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $groups = $selectionList->getEntityListGroups(); $this->updateTarget, foreach ($groups as $eachGroup) { $selectionList->getNormalPriorityEntityId() $groupEntityIds = $selectionList->getEntityListItemsByGroup($eachGroup); ); if (! empty($groupEntityIds)) { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $this->updateTarget, entityType: $this->updateTarget, $selectionList->getHighPriorityEntityIds(), entityIds: $groupEntityIds, true priority: QueuePriorityEnum::tryFromString($eachGroup) ); ); } } } } } } app/Console/Commands/Elasticsearch/AsyncUpdateEsEntities.php +9-3Lines changed: 9 additions & 3 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Illuminate\Support\Str; use Illuminate\Support\Str; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Component\ES\UpdateProcessManager; use Jiminny\Component\ES\UpdateProcessManager; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Traits\GracefullyStoppable; use Jiminny\Traits\GracefullyStoppable; Redis::set($gaugeLockName, true); Redis::set($gaugeLockName, true); Redis::expire($gaugeLockName, 60); Redis::expire($gaugeLockName, 60); $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::HIGH), ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update', $updateTarget), stat: sprintf('jiminny.%s-for-update', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::NORMAL), ); ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), stat: sprintf('jiminny.%s-for-update-low', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, true), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::LOW), ); ); } } app/Console/Commands/Elasticsearch/ResetAsyncElasticSearchCommand.php +5-1Lines changed: 5 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\Traits\ValidateUpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\ValidateUpdateTargetTrait; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Component\ES\Repositories\EsResetRepositoryInterface; use Jiminny\Component\ES\Repositories\EsResetRepositoryInterface; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Traits\GracefullyStoppable; use Jiminny\Traits\GracefullyStoppable; private function getRemainingScheduledEntities(bool $printStatus = false): int private function getRemainingScheduledEntities(bool $printStatus = false): int { { $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget, true); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount( $this->updateTarget, QueuePriorityEnum::HIGH ); if ($printStatus) { if ($printStatus) { $this->line( $this->line(
You said
app/Component/ES/Listeners/UpdateMultipleTargetsListener.php
+2-1Lines changed: 2 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\Component\ES\Listeners;
namespace Jiminny\Component\ES\Listeners;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\QueuePriorityEnum;
use Jiminny\Contracts\ES\Events\UpdateMultipleEntities;
use Jiminny\Contracts\ES\Events\UpdateMultipleEntities;
use Psr\Log\LoggerInterface;
use Psr\Log\LoggerInterface;
AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(
AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(
$event->getUpdateTargetValue(),
$event->getUpdateTargetValue(),
$event->getEntities(),
$event->getEntities(),
$event->isPriority()
$event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL,
);
);
}
}
}
}
app/Component/ES/Listeners/UpdateSingleTargetListener.php
+9-1Lines changed: 9 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Actions\TrackElasticSearchOperations;
use Jiminny\Component\ES\Actions\TrackElasticSearchOperations;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\Processor\EntityQueryBuilder;
use Jiminny\Component\ES\Processor\EntityQueryBuilder;
use Jiminny\Component\ES\QueuePriorityEnum;
use Jiminny\Contracts\ES\Events\UpdateSingleEntity;
use Jiminny\Contracts\ES\Events\UpdateSingleEntity;
use Psr\Log\LoggerInterface;
use Psr\Log\LoggerInterface;
'entityId' => $event->getEntityId(),
'entityId' => $event->getEntityId(),
]);
]);
/**
* @important:
* Synchronous event should eventually be deprecated.
* Instant write operations are blocking and should be used sparingly.
* It is much better in terms of performance to write 100 or 1000 documents at once,
* and have one blocking reindex operation, instead of writing 10 documents synchronously.
*/
if ($event->isSyncEvent()) {
if ($event->isSyncEvent()) {
$this->handleSyncEvent($event);
$this->handleSyncEvent($event);
AsyncUpdateElasticSearch::markEntityForUpdate(
AsyncUpdateElasticSearch::markEntityForUpdate(
$event->getUpdateTargetValue(),
$event->getUpdateTargetValue(),
$event->getEntityId(),
$event->getEntityId(),
$event->isPriority()
$event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL,
);
);
}
}
app/Component/ES/Processor/Actions/UpsertDocumentsAction.php
+2-1Lines changed: 2 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SimpleCollection;
use Jiminny\Component\ES\Processor\DTOs\SimpleCollection;
use Jiminny\Component\ES\Processor\ResponseEvaluator;
use Jiminny\Component\ES\Processor\ResponseEvaluator;
use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait;
use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait;
use Jiminny\Component\ES\QueuePriorityEnum;
use Jiminny\Exceptions\InvalidDataException;
use Jiminny\Exceptions\InvalidDataException;
use Sentry\Laravel\Facade as Sentry;
use Sentry\Laravel\Facade as Sentry;
AsyncUpdateElasticSearch::markEntityForUpdate(
AsyncUpdateElasticSearch::markEntityForUpdate(
entityType: $this->updateTarget,
entityType: $this->updateTarget,
entityId: (int) $document->getId(),
entityId: (int) $document->getId(),
withPriority: true
priority: QueuePriorityEnum::HIGH,
);
);
}
}
app/Component/ES/Processor/DTOs/SelectionList.php
+54-17Lines changed: 54 additions & 17 deletions
Original file line numberOriginal file lineDiff line numberDiff line change
namespace Jiminny\Component\ES\Processor\DTOs;
namespace Jiminny\Component\ES\Processor\DTOs;
use Jiminny\Component\ES\QueuePriorityEnum;
/**
/**
* A very basic and simple collection of entity IDs.
* A very basic and simple collection of entity IDs.
*/
*/
class SelectionList
class SelectionList
{
{
public function __construct(
private const int DEFAULT_CHUNK = 200;
private readonly array $priorityEntityIdList = [],
private readonly array $normalEntityIdList = [],
private int $chunkSize = self::DEFAULT_CHUNK;
private readonly bool $isStaleChunkSelected = false,
private bool $isStaleChunkSelected = false;
private readonly int $chunkSize = 200,
private array $selectedEntityIds = [];
) {
// Do nothing
public function setChunkSize(int $chunkSize): void
{
$this->chunkSize = $chunkSize;
}
}
public function getAllIds(): array
public function markStale(): void
{
{
return array_merge($this->priorityEntityIdList, $this->normalEntityIdList);
$this->isStaleChunkSelected = true;
}
}
public function count(): int
public function addEntityList(string|QueuePriorityEnum $priority, array $entityIds): void
{
{
return count($this->priorityEntityIdList) + count($this->normalEntityIdList);
$priorityKey = $this->normalisePriority($priority);
if (! array_key_exists($priorityKey, $this->selectedEntityIds)) {
$this->selectedEntityIds[$priorityKey] = [];
}
$this->selectedEntityIds[$priorityKey] = array_merge($this->selectedEntityIds[$priorityKey], $entityIds);
}
}
public function isEmpty(): bool
/**
* @return string[]
*/
public function getEntityListGroups(): array
{
{
return empty($this->priorityEntityIdList) && empty($this->normalEntityIdList);
return array_keys($this->selectedEntityIds);
}
}
public function getHighPriorityEntityIds(): array
public function getEntityListItemsByGroup(string|QueuePriorityEnum $priority): array
{
{
return $this->priorityEntityIdList;
$priorityKey = $this->normalisePriority($priority);
return $this->selectedEntityIds[$priorityKey] ?? [];
}
}
public function getNormalPriorityEntityId(): array
public function getAllIds(): array
{
{
return $this->normalEntityIdList;
$allIds = [];
foreach ($this->selectedEntityIds as $entityIds) {
$allIds = array_merge($allIds, $entityIds);
}
return $allIds;
}
public function count(): int
{
return array_sum(
array_map('count', $this->selectedEntityIds)
);
}
public function isEmpty(): bool
{
return $this->count() === 0;
}
}...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira","depth":4,"bounds":{"left":0.0,"top":0.0518755,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.06304868,"width":0.10106383,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app","depth":4,"bounds":{"left":0.0,"top":0.08459697,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app","depth":5,"bounds":{"left":0.013297873,"top":0.09577015,"width":0.18816489,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app","depth":4,"bounds":{"left":0.0,"top":0.11731844,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app","depth":5,"bounds":{"left":0.013297873,"top":0.12849163,"width":0.15674867,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.06732048,"top":0.1245012,"width":0.007978723,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New Tab","depth":4,"bounds":{"left":0.0028257978,"top":0.15163608,"width":0.07413564,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"bounds":{"left":0.0028257978,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Close Google Gemini (⌃X)","depth":6,"bounds":{"left":0.013796543,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Tabs from other devices","depth":6,"bounds":{"left":0.024933511,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"bounds":{"left":0.036070477,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"bounds":{"left":0.04720745,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"AI Chat settings","depth":7,"bounds":{"left":0.35854387,"top":0.055067837,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Close","depth":7,"bounds":{"left":0.37051198,"top":0.055067837,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"WORK, Google Account: lukas.kovalik@jiminny.com","depth":12,"bounds":{"left":0.3678524,"top":0.103751,"width":0.013297873,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Main menu","depth":12,"bounds":{"left":0.08494016,"top":0.103751,"width":0.013297873,"height":0.031923383},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New chat","depth":12,"bounds":{"left":0.09823803,"top":0.10454908,"width":0.028590426,"height":0.030327214},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Gemini","depth":15,"bounds":{"left":0.1008976,"top":0.10973663,"width":0.021941489,"height":0.020351157},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"New Chat","depth":12,"bounds":{"left":0.33992687,"top":0.103751,"width":0.013297873,"height":0.031923383},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Open menu for conversation actions.","depth":12,"bounds":{"left":0.35322472,"top":0.103751,"width":0.013297873,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXHeading","text":"Conversation with Gemini","depth":15,"bounds":{"left":0.079288565,"top":0.14764565,"width":0.0003324468,"height":0.0007980846},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Conversation with Gemini","depth":16,"bounds":{"left":0.079288565,"top":0.15003991,"width":0.1200133,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Show the uploaded image in a lightbox","depth":21,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy prompt","depth":21,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"You said Make a PR of changes Find potential issues and bottlenecks","depth":21,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"You said","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Make a PR of changes Find potential issues and bottlenecks","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Listen","depth":22,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Show thinking","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Gemini said","depth":20,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Gemini said","depth":21,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"I can see you've uploaded a screenshot of a code diff, likely from a version control system given the red and green highlights. I would love to help you review the changes, spot bottlenecks, and help you draft a Pull Request.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"However,","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"the image resolution is far too low for me to read.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"It appears to be a completely zoomed-out view where the code has been reduced to tiny, illegible pixels. Because of this, I cannot extract any text or logic to analyze.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"How You Can Share the Code","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"How You Can Share the Code","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"To help me review your code effectively, please try one of the following:","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Paste the text directly:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Copy the specific code blocks (both the old and new versions if possible) and paste them directly into our chat.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Upload the files:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"If the changes are extensive, you can upload the raw text or code files.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Take high-resolution screenshots:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"If you must use images, take closer, readable screenshots of the specific functions or methods you want me to review.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Once you provide the readable code, I can dive right in to identify potential bugs, assess performance bottlenecks, and help you summarize the changes for your PR!","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Good response","depth":22,"on_screen":false,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Bad response","depth":22,"on_screen":false,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Share & export","depth":21,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy","depth":22,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Show more options","depth":21,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy prompt","depth":21,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Edit","depth":21,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"You said app/Component/ES/Listeners/UpdateMultipleTargetsListener.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\\Component\\ES\\Listeners; namespace Jiminny\\Component\\ES\\Listeners; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Contracts\\ES\\Events\\UpdateMultipleEntities; use Jiminny\\Contracts\\ES\\Events\\UpdateMultipleEntities; use Psr\\Log\\LoggerInterface; use Psr\\Log\\LoggerInterface; AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntities(), $event->getEntities(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } } } app/Component/ES/Listeners/UpdateSingleTargetListener.php +9-1Lines changed: 9 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Actions\\TrackElasticSearchOperations; use Jiminny\\Component\\ES\\Actions\\TrackElasticSearchOperations; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder; use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Contracts\\ES\\Events\\UpdateSingleEntity; use Jiminny\\Contracts\\ES\\Events\\UpdateSingleEntity; use Psr\\Log\\LoggerInterface; use Psr\\Log\\LoggerInterface; 'entityId' => $event->getEntityId(), 'entityId' => $event->getEntityId(), ]); ]); /** * @important: * Synchronous event should eventually be deprecated. * Instant write operations are blocking and should be used sparingly. * It is much better in terms of performance to write 100 or 1000 documents at once, * and have one blocking reindex operation, instead of writing 10 documents synchronously. */ if ($event->isSyncEvent()) { if ($event->isSyncEvent()) { $this->handleSyncEvent($event); $this->handleSyncEvent($event); AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntityId(), $event->getEntityId(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } app/Component/ES/Processor/Actions/UpsertDocumentsAction.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Processor\\DTOs\\SimpleCollection; use Jiminny\\Component\\ES\\Processor\\DTOs\\SimpleCollection; use Jiminny\\Component\\ES\\Processor\\ResponseEvaluator; use Jiminny\\Component\\ES\\Processor\\ResponseEvaluator; use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait; use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Exceptions\\InvalidDataException; use Jiminny\\Exceptions\\InvalidDataException; use Sentry\\Laravel\\Facade as Sentry; use Sentry\\Laravel\\Facade as Sentry; AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( entityType: $this->updateTarget, entityType: $this->updateTarget, entityId: (int) $document->getId(), entityId: (int) $document->getId(), withPriority: true priority: QueuePriorityEnum::HIGH, ); ); } } app/Component/ES/Processor/DTOs/SelectionList.php +54-17Lines changed: 54 additions & 17 deletions Original file line numberOriginal file lineDiff line numberDiff line change namespace Jiminny\\Component\\ES\\Processor\\DTOs; namespace Jiminny\\Component\\ES\\Processor\\DTOs; use Jiminny\\Component\\ES\\QueuePriorityEnum; /** /** * A very basic and simple collection of entity IDs. * A very basic and simple collection of entity IDs. */ */ class SelectionList class SelectionList { { public function __construct( private const int DEFAULT_CHUNK = 200; private readonly array $priorityEntityIdList = [], private readonly array $normalEntityIdList = [], private int $chunkSize = self::DEFAULT_CHUNK; private readonly bool $isStaleChunkSelected = false, private bool $isStaleChunkSelected = false; private readonly int $chunkSize = 200, private array $selectedEntityIds = []; ) { // Do nothing public function setChunkSize(int $chunkSize): void { $this->chunkSize = $chunkSize; } } public function getAllIds(): array public function markStale(): void { { return array_merge($this->priorityEntityIdList, $this->normalEntityIdList); $this->isStaleChunkSelected = true; } } public function count(): int public function addEntityList(string|QueuePriorityEnum $priority, array $entityIds): void { { return count($this->priorityEntityIdList) + count($this->normalEntityIdList); $priorityKey = $this->normalisePriority($priority); if (! array_key_exists($priorityKey, $this->selectedEntityIds)) { $this->selectedEntityIds[$priorityKey] = []; } $this->selectedEntityIds[$priorityKey] = array_merge($this->selectedEntityIds[$priorityKey], $entityIds); } } public function isEmpty(): bool /** * @return string[] */ public function getEntityListGroups(): array { { return empty($this->priorityEntityIdList) && empty($this->normalEntityIdList); return array_keys($this->selectedEntityIds); } } public function getHighPriorityEntityIds(): array public function getEntityListItemsByGroup(string|QueuePriorityEnum $priority): array { { return $this->priorityEntityIdList; $priorityKey = $this->normalisePriority($priority); return $this->selectedEntityIds[$priorityKey] ?? []; } } public function getNormalPriorityEntityId(): array public function getAllIds(): array { { return $this->normalEntityIdList; $allIds = []; foreach ($this->selectedEntityIds as $entityIds) { $allIds = array_merge($allIds, $entityIds); } return $allIds; } public function count(): int { return array_sum( array_map('count', $this->selectedEntityIds) ); } public function isEmpty(): bool { return $this->count() === 0; } } public function isStaleChunkSelected(): bool public function isStaleChunkSelected(): bool { { return $this->count() >= $this->chunkSize; return $this->count() >= $this->chunkSize; } } private function normalisePriority(string|QueuePriorityEnum $priority): string { return $priority instanceof QueuePriorityEnum ? $priority->value : $priority; } } } app/Component/ES/Processor/Traits/SelectEntityListTrait.php +27-4Lines changed: 27 additions & 4 deletions Original file line numberOriginal file lineDiff line numberDiff line change use Illuminate\\Support\\Facades\\Log; use Illuminate\\Support\\Facades\\Log; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Exceptions\\InvalidArgumentException; use Jiminny\\Exceptions\\InvalidArgumentException; /** /** * Build the correct source list name for the type of entity and priority * Build the correct source list name for the type of entity and priority */ */ trait SelectEntityListTrait trait SelectEntityListTrait { { /** * Highest priority queue for data requiring near-instant availability. * Very few entities should be added here, only when absolutely necessary. */ private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; /** * Normal priority queue for normal application operations. * Almost all update events should pass through this queue */ private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; protected static function selectTargetList(string $entityType, bool $withPriority = false): string /** { * Nonblocking low priority queue. This queue will be consumed only when there is nothing * with higher priority. * * This queue will be used for operations such as es:reset-async */ private const string ENTITIES_LOW_PRIORITIES_LIST = '%s-for-update-low'; protected static function selectTargetList( string $entityType, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { if (! in_array($entityType, UpdateTarget::allowedTargets())) { if (! in_array($entityType, UpdateTarget::allowedTargets())) { throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); } } if ($withPriority) { if ($priority->isHigh()) { Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); } } if ($priority->isLow()) { return sprintf(self::ENTITIES_LOW_PRIORITIES_LIST, $entityType); } return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); } } } } app/Component/ES/Processor/TargetEntitiesSelector.php +26-21Lines changed: 26 additions & 21 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Processor\\DTOs\\SelectionList; use Jiminny\\Component\\ES\\Processor\\DTOs\\SelectionList; use Jiminny\\Component\\ES\\Processor\\Traits\\ExtractIdsTrait; use Jiminny\\Component\\ES\\Processor\\Traits\\ExtractIdsTrait; use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait; use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait; use Jiminny\\Component\\ES\\QueuePriorityEnum; /** /** * This class supplies a list of entities pending an update. * This class supplies a list of entities pending an update. public function select(): SelectionList public function select(): SelectionList { { $staleWorkEntityIds = $this->getStaleChunk(); $selectionList = new SelectionList(); $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $staleWorkEntityIds = $this->getStaleChunk(); if (count($staleWorkEntityIds) > 0) { if (count($staleWorkEntityIds) > 0) { return new SelectionList( /** priorityEntityIdList: $staleWorkEntityIds, * Stale chunks are treated as high priority isStaleChunkSelected: true, */ chunkSize: ChunkSize::getStaleChunkSize($this->updateTarget), $selectionList->markStale(); ); $selectionList->addEntityList(QueuePriorityEnum::HIGH, $staleWorkEntityIds); $selectionList->setChunkSize(ChunkSize::getStaleChunkSize($this->updateTarget)); return $selectionList; } } $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $selectionList->setChunkSize($mainChunkSize); $priorityEntityIdsList = $this->extractIdsFromSet( $priorityEntityIdsList = $this->extractIds(QueuePriorityEnum::HIGH, $mainChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, true), $selectionList->addEntityList(QueuePriorityEnum::HIGH, $priorityEntityIdsList); $mainChunkSize, ); $normalEntityIdsList = []; $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); if ($normalEntityChunkSize > 0) { if ($normalEntityChunkSize > 0) { $normalEntityIdsList = $this->extractIdsFromSet( $normalEntityIdsList = $this->extractIds(QueuePriorityEnum::NORMAL, $normalEntityChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, false), $selectionList->addEntityList(QueuePriorityEnum::NORMAL, $normalEntityIdsList); $normalEntityChunkSize ); } } return new SelectionList( return $selectionList; priorityEntityIdList: $priorityEntityIdsList, normalEntityIdList: $normalEntityIdsList, chunkSize: $mainChunkSize ); } } private function getStaleChunk(): array private function getStaleChunk(): array return []; return []; } } private function extractIds(QueuePriorityEnum $priority, int $chunkSize): array { return $this->extractIdsFromSet( AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, $priority), $chunkSize ); } } } app/Component/ES/AsyncUpdateElasticSearch.php +17-10Lines changed: 17 additions & 10 deletions Original file line numberOriginal file lineDiff line numberDiff line change * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * and other activity related data * and other activity related data */ */ public static function markEntityForUpdate(string $entityType, int $entityId, bool $withPriority = false): void public static function markEntityForUpdate( { string $entityType, $targetList = self::selectTargetList($entityType, $withPriority); int $entityId, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { $targetList = self::selectTargetList($entityType, $priority); Redis::sadd($targetList, $entityId); Redis::sadd($targetList, $entityId); Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ 'entityType' => $entityType, 'entityType' => $entityType, 'entityId' => $entityId, 'entityId' => $entityId, 'collectionKey' => $targetList, 'collectionKey' => $targetList, 'withPriority' => $withPriority, 'priority' => $priority->value, ]); ]); } } public static function bulkMarkEntitiesForUpdate( public static function bulkMarkEntitiesForUpdate( string $entityType, string $entityType, array $entityIds, array $entityIds, bool $withPriority = false QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { ): void { if (empty($entityIds)) { if (empty($entityIds)) { return; return; } } $targetList = self::selectTargetList($entityType, $withPriority); $targetList = self::selectTargetList($entityType, $priority); Redis::saddarray($targetList, $entityIds); Redis::saddarray($targetList, $entityIds); } } * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Takes priority into consideration. * Takes priority into consideration. */ */ public static function getEntitiesSourceList(string $updateTarget, $priority = false): string public static function getEntitiesSourceList( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { return self::selectTargetList($updateTarget, $priority); return self::selectTargetList($updateTarget, $priority); } } /** /** * Externally called helper methods * Externally called helper methods * - count and flush * - count and flush */ */ public static function getEntitiesListCount(string $updateTarget, $priority = false): int public static function getEntitiesListCount( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): int { $targetList = self::selectTargetList($updateTarget, $priority); $targetList = self::selectTargetList($updateTarget, $priority); return Redis::scard($targetList); return Redis::scard($targetList); app/Component/ES/QueuePriorityEnum.php +40Lines changed: 40 additions & 0 deletions Original file line numberOriginal file lineDiff line numberDiff line change <?php declare(strict_types=1); namespace Jiminny\\Component\\ES; use Jiminny\\Exceptions\\InvalidArgumentException; enum QueuePriorityEnum: string { case HIGH = 'high'; case NORMAL = 'normal'; case LOW = 'low'; public static function tryFromString(string $value): self { if (! self::isValid($value)) { throw new InvalidArgumentException( sprintf('Invalid queue priority \"%s\" selected', $value) ); } return self::tryFrom($value); } public static function isValid(string $value): bool { return self::tryFrom($value) !== null; } public function isLow(): bool { return $this === self::LOW; } public function isHigh(): bool { return $this === self::HIGH; } } app/Component/ES/UpdateProcessManager.php +12-9Lines changed: 12 additions & 9 deletions Original file line numberOriginal file lineDiff line numberDiff line change if ($selectionList->isEmpty()) { if ($selectionList->isEmpty()) { return false; return false; } } /** /** * A stale chunk will always be smaller than a regular chunk. * A stale chunk will always be smaller than a regular chunk. * That doesn't mean there aren't any other scheduled entities for processing * That doesn't mean there aren't any other scheduled entities for processing private function rescheduleThrottledEntities(SelectionList $selectionList): void private function rescheduleThrottledEntities(SelectionList $selectionList): void { { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $groups = $selectionList->getEntityListGroups(); $this->updateTarget, foreach ($groups as $eachGroup) { $selectionList->getNormalPriorityEntityId() $groupEntityIds = $selectionList->getEntityListItemsByGroup($eachGroup); ); if (! empty($groupEntityIds)) { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $this->updateTarget, entityType: $this->updateTarget, $selectionList->getHighPriorityEntityIds(), entityIds: $groupEntityIds, true priority: QueuePriorityEnum::tryFromString($eachGroup) ); ); } } } } } } app/Console/Commands/Elasticsearch/AsyncUpdateEsEntities.php +9-3Lines changed: 9 additions & 3 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Illuminate\\Support\\Str; use Illuminate\\Support\\Str; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Component\\ES\\UpdateProcessManager; use Jiminny\\Component\\ES\\UpdateProcessManager; use Jiminny\\Exceptions\\InvalidArgumentException; use Jiminny\\Exceptions\\InvalidArgumentException; use Jiminny\\Traits\\GracefullyStoppable; use Jiminny\\Traits\\GracefullyStoppable; Redis::set($gaugeLockName, true); Redis::set($gaugeLockName, true); Redis::expire($gaugeLockName, 60); Redis::expire($gaugeLockName, 60); $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::HIGH), ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update', $updateTarget), stat: sprintf('jiminny.%s-for-update', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::NORMAL), ); ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), stat: sprintf('jiminny.%s-for-update-low', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, true), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::LOW), ); ); } } app/Console/Commands/Elasticsearch/ResetAsyncElasticSearchCommand.php +5-1Lines changed: 5 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder; use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder; use Jiminny\\Component\\ES\\Processor\\Traits\\ValidateUpdateTargetTrait; use Jiminny\\Component\\ES\\Processor\\Traits\\ValidateUpdateTargetTrait; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Component\\ES\\Repositories\\EsResetRepositoryInterface; use Jiminny\\Component\\ES\\Repositories\\EsResetRepositoryInterface; use Jiminny\\Exceptions\\InvalidArgumentException; use Jiminny\\Exceptions\\InvalidArgumentException; use Jiminny\\Traits\\GracefullyStoppable; use Jiminny\\Traits\\GracefullyStoppable; private function getRemainingScheduledEntities(bool $printStatus = false): int private function getRemainingScheduledEntities(bool $printStatus = false): int { { $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget, true); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount( $this->updateTarget, QueuePriorityEnum::HIGH ); if ($printStatus) { if ($printStatus) { $this->line( $this->line(","depth":21,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"You said","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app/Component/ES/Listeners/UpdateMultipleTargetsListener.php","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"+2-1Lines changed: 2 additions & 1 deletion","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\\Component\\ES\\Listeners;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"namespace Jiminny\\Component\\ES\\Listeners;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\QueuePriorityEnum;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Contracts\\ES\\Events\\UpdateMultipleEntities;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Contracts\\ES\\Events\\UpdateMultipleEntities;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Psr\\Log\\LoggerInterface;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Psr\\Log\\LoggerInterface;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getUpdateTargetValue(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getUpdateTargetValue(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getEntities(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getEntities(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->isPriority()","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL,","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":");","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":");","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app/Component/ES/Listeners/UpdateSingleTargetListener.php","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"+9-1Lines changed: 9 additions & 1 deletion","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Actions\\TrackElasticSearchOperations;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Actions\\TrackElasticSearchOperations;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\QueuePriorityEnum;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Contracts\\ES\\Events\\UpdateSingleEntity;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Contracts\\ES\\Events\\UpdateSingleEntity;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Psr\\Log\\LoggerInterface;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Psr\\Log\\LoggerInterface;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"'entityId' => $event->getEntityId(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"'entityId' => $event->getEntityId(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"]);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"]);","depth":23,"bounds":{"left":0.20578457,"top":0.0,"width":0.0051529254,"height":0.016360734},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/**","depth":23,"bounds":{"left":0.20578457,"top":0.00518755,"width":0.0066489363,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* @important:","depth":23,"bounds":{"left":0.20578457,"top":0.06264964,"width":0.03374335,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* Synchronous event should eventually be deprecated.","depth":23,"bounds":{"left":0.20578457,"top":0.12011173,"width":0.13131648,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* Instant write operations are blocking and should be used sparingly.","depth":23,"bounds":{"left":0.20578457,"top":0.17757383,"width":0.12732713,"height":0.035514764},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* It is much better in terms of performance to write 100 or 1000 documents at once,","depth":23,"bounds":{"left":0.20578457,"top":0.25418994,"width":0.13314494,"height":0.035514764},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* and have one blocking reindex operation, instead of writing 10 documents synchronously.","depth":23,"bounds":{"left":0.20578457,"top":0.33080608,"width":0.12865691,"height":0.035514764},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"*/","depth":23,"bounds":{"left":0.20578457,"top":0.40742218,"width":0.004155585,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"if ($event->isSyncEvent()) {","depth":23,"bounds":{"left":0.20578457,"top":0.42657623,"width":0.065990694,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"if ($event->isSyncEvent()) {","depth":23,"bounds":{"left":0.20578457,"top":0.44573024,"width":0.065990694,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$this->handleSyncEvent($event);","depth":23,"bounds":{"left":0.20578457,"top":0.46488428,"width":0.08028591,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$this->handleSyncEvent($event);","depth":23,"bounds":{"left":0.20578457,"top":0.4840383,"width":0.08028591,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AsyncUpdateElasticSearch::markEntityForUpdate(","depth":23,"bounds":{"left":0.20578457,"top":0.5415004,"width":0.12117686,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AsyncUpdateElasticSearch::markEntityForUpdate(","depth":23,"bounds":{"left":0.20578457,"top":0.5606544,"width":0.12117686,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getUpdateTargetValue(),","depth":23,"bounds":{"left":0.20578457,"top":0.5798085,"width":0.0809508,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getUpdateTargetValue(),","depth":23,"bounds":{"left":0.20578457,"top":0.5989625,"width":0.0809508,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getEntityId(),","depth":23,"bounds":{"left":0.20578457,"top":0.6181165,"width":0.053025264,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getEntityId(),","depth":23,"bounds":{"left":0.20578457,"top":0.63727057,"width":0.053025264,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->isPriority()","depth":23,"bounds":{"left":0.20578457,"top":0.6564246,"width":0.046708778,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL,","depth":23,"bounds":{"left":0.20578457,"top":0.6755786,"width":0.11702128,"height":0.035514764},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":");","depth":23,"bounds":{"left":0.20578457,"top":0.7138867,"width":0.0033244682,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":");","depth":23,"bounds":{"left":0.20578457,"top":0.7330407,"width":0.0033244682,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"bounds":{"left":0.20578457,"top":0.75219476,"width":0.0019946808,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"bounds":{"left":0.20578457,"top":0.7713488,"width":0.0019946808,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app/Component/ES/Processor/Actions/UpsertDocumentsAction.php","depth":23,"bounds":{"left":0.20578457,"top":0.8288109,"width":0.09375,"height":0.035514764},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"+2-1Lines changed: 2 additions & 1 deletion","depth":23,"bounds":{"left":0.20578457,"top":0.88627297,"width":0.10388963,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Processor\\DTOs\\SimpleCollection;","depth":23,"bounds":{"left":0.20578457,"top":0.924581,"width":0.1356383,"height":0.073822826},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\DTOs\\SimpleCollection;","depth":23,"bounds":{"left":0.20578457,"top":1.0,"width":0.1356383,"height":-0.0011970997},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\ResponseEvaluator;","depth":23,"bounds":{"left":0.20578457,"top":1.0,"width":0.13115026,"height":-0.058659196},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\ResponseEvaluator;","depth":23,"bounds":{"left":0.20578457,"top":1.0,"width":0.13115026,"height":-0.09696722},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\QueuePriorityEnum;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Exceptions\\InvalidDataException;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Exceptions\\InvalidDataException;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Sentry\\Laravel\\Facade as Sentry;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Sentry\\Laravel\\Facade as Sentry;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AsyncUpdateElasticSearch::markEntityForUpdate(","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AsyncUpdateElasticSearch::markEntityForUpdate(","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"entityType: $this->updateTarget,","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"entityType: $this->updateTarget,","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"entityId: (int) $document->getId(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"entityId: (int) $document->getId(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"withPriority: true","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"priority: QueuePriorityEnum::HIGH,","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":");","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":");","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app/Component/ES/Processor/DTOs/SelectionList.php","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"+54-17Lines changed: 54 additions & 17 deletions","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Original file line numberOriginal file lineDiff line numberDiff line change","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"namespace Jiminny\\Component\\ES\\Processor\\DTOs;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"namespace Jiminny\\Component\\ES\\Processor\\DTOs;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\QueuePriorityEnum;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/**","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/**","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* A very basic and simple collection of entity IDs.","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* A very basic and simple collection of entity IDs.","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"*/","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"*/","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"class SelectionList","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"class SelectionList","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function __construct(","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private const int DEFAULT_CHUNK = 200;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private readonly array $priorityEntityIdList = [],","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private readonly array $normalEntityIdList = [],","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private int $chunkSize = self::DEFAULT_CHUNK;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private readonly bool $isStaleChunkSelected = false,","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private bool $isStaleChunkSelected = false;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private readonly int $chunkSize = 200,","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private array $selectedEntityIds = [];","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":") {","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"// Do nothing","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function setChunkSize(int $chunkSize): void","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$this->chunkSize = $chunkSize;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function getAllIds(): array","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function markStale(): void","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"return array_merge($this->priorityEntityIdList, $this->normalEntityIdList);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$this->isStaleChunkSelected = true;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function count(): int","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function addEntityList(string|QueuePriorityEnum $priority, array $entityIds): void","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"return count($this->priorityEntityIdList) + count($this->normalEntityIdList);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$priorityKey = $this->normalisePriority($priority);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"if (! array_key_exists($priorityKey, $this->selectedEntityIds)) {","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$this->selectedEntityIds[$priorityKey] = [];","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$this->selectedEntityIds[$priorityKey] = array_merge($this->selectedEntityIds[$priorityKey], $entityIds);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function isEmpty(): bool","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/**","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* @return string[]","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"*/","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function getEntityListGroups(): array","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"return empty($this->priorityEntityIdList) && empty($this->normalEntityIdList);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"return array_keys($this->selectedEntityIds);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function getHighPriorityEntityIds(): array","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function getEntityListItemsByGroup(string|QueuePriorityEnum $priority): array","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"return $this->priorityEntityIdList;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$priorityKey = $this->normalisePriority($priority);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"return $this->selectedEntityIds[$priorityKey] ?? [];","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function getNormalPriorityEntityId(): array","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function getAllIds(): array","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"return $this->normalEntityIdList;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$allIds = [];","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"foreach ($this->selectedEntityIds as $entityIds) {","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$allIds = array_merge($allIds, $entityIds);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"return $allIds;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function count(): int","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"return array_sum(","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"array_map('count', $this->selectedEntityIds)","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":");","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function isEmpty(): bool","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"return $this->count() === 0;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"}]...
|
-3411995691327326678
|
-1144453838252598132
|
visual_change
|
accessibility
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
Close tab
New Tab
Customize sidebar
Close Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
AI Chat settings
Close
WORK, Google Account: [EMAIL]
Main menu
New chat
Gemini
New Chat
Open menu for conversation actions.
Conversation with Gemini
Conversation with Gemini
Show the uploaded image in a lightbox
Copy prompt
You said Make a PR of changes Find potential issues and bottlenecks
You said
Make a PR of changes Find potential issues and bottlenecks
Listen
Show thinking
Gemini said
Gemini said
I can see you've uploaded a screenshot of a code diff, likely from a version control system given the red and green highlights. I would love to help you review the changes, spot bottlenecks, and help you draft a Pull Request.
However,
the image resolution is far too low for me to read.
It appears to be a completely zoomed-out view where the code has been reduced to tiny, illegible pixels. Because of this, I cannot extract any text or logic to analyze.
How You Can Share the Code
How You Can Share the Code
To help me review your code effectively, please try one of the following:
Paste the text directly:
Copy the specific code blocks (both the old and new versions if possible) and paste them directly into our chat.
Upload the files:
If the changes are extensive, you can upload the raw text or code files.
Take high-resolution screenshots:
If you must use images, take closer, readable screenshots of the specific functions or methods you want me to review.
Once you provide the readable code, I can dive right in to identify potential bugs, assess performance bottlenecks, and help you summarize the changes for your PR!
Good response
Bad response
Share & export
Copy
Show more options
Copy prompt
Edit
You said app/Component/ES/Listeners/UpdateMultipleTargetsListener.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\Component\ES\Listeners; namespace Jiminny\Component\ES\Listeners; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Contracts\ES\Events\UpdateMultipleEntities; use Jiminny\Contracts\ES\Events\UpdateMultipleEntities; use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface; AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntities(), $event->getEntities(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } } } app/Component/ES/Listeners/UpdateSingleTargetListener.php +9-1Lines changed: 9 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Actions\TrackElasticSearchOperations; use Jiminny\Component\ES\Actions\TrackElasticSearchOperations; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Contracts\ES\Events\UpdateSingleEntity; use Jiminny\Contracts\ES\Events\UpdateSingleEntity; use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface; 'entityId' => $event->getEntityId(), 'entityId' => $event->getEntityId(), ]); ]); /** * @important: * Synchronous event should eventually be deprecated. * Instant write operations are blocking and should be used sparingly. * It is much better in terms of performance to write 100 or 1000 documents at once, * and have one blocking reindex operation, instead of writing 10 documents synchronously. */ if ($event->isSyncEvent()) { if ($event->isSyncEvent()) { $this->handleSyncEvent($event); $this->handleSyncEvent($event); AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntityId(), $event->getEntityId(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } app/Component/ES/Processor/Actions/UpsertDocumentsAction.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SimpleCollection; use Jiminny\Component\ES\Processor\DTOs\SimpleCollection; use Jiminny\Component\ES\Processor\ResponseEvaluator; use Jiminny\Component\ES\Processor\ResponseEvaluator; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Exceptions\InvalidDataException; use Jiminny\Exceptions\InvalidDataException; use Sentry\Laravel\Facade as Sentry; use Sentry\Laravel\Facade as Sentry; AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( entityType: $this->updateTarget, entityType: $this->updateTarget, entityId: (int) $document->getId(), entityId: (int) $document->getId(), withPriority: true priority: QueuePriorityEnum::HIGH, ); ); } } app/Component/ES/Processor/DTOs/SelectionList.php +54-17Lines changed: 54 additions & 17 deletions Original file line numberOriginal file lineDiff line numberDiff line change namespace Jiminny\Component\ES\Processor\DTOs; namespace Jiminny\Component\ES\Processor\DTOs; use Jiminny\Component\ES\QueuePriorityEnum; /** /** * A very basic and simple collection of entity IDs. * A very basic and simple collection of entity IDs. */ */ class SelectionList class SelectionList { { public function __construct( private const int DEFAULT_CHUNK = 200; private readonly array $priorityEntityIdList = [], private readonly array $normalEntityIdList = [], private int $chunkSize = self::DEFAULT_CHUNK; private readonly bool $isStaleChunkSelected = false, private bool $isStaleChunkSelected = false; private readonly int $chunkSize = 200, private array $selectedEntityIds = []; ) { // Do nothing public function setChunkSize(int $chunkSize): void { $this->chunkSize = $chunkSize; } } public function getAllIds(): array public function markStale(): void { { return array_merge($this->priorityEntityIdList, $this->normalEntityIdList); $this->isStaleChunkSelected = true; } } public function count(): int public function addEntityList(string|QueuePriorityEnum $priority, array $entityIds): void { { return count($this->priorityEntityIdList) + count($this->normalEntityIdList); $priorityKey = $this->normalisePriority($priority); if (! array_key_exists($priorityKey, $this->selectedEntityIds)) { $this->selectedEntityIds[$priorityKey] = []; } $this->selectedEntityIds[$priorityKey] = array_merge($this->selectedEntityIds[$priorityKey], $entityIds); } } public function isEmpty(): bool /** * @return string[] */ public function getEntityListGroups(): array { { return empty($this->priorityEntityIdList) && empty($this->normalEntityIdList); return array_keys($this->selectedEntityIds); } } public function getHighPriorityEntityIds(): array public function getEntityListItemsByGroup(string|QueuePriorityEnum $priority): array { { return $this->priorityEntityIdList; $priorityKey = $this->normalisePriority($priority); return $this->selectedEntityIds[$priorityKey] ?? []; } } public function getNormalPriorityEntityId(): array public function getAllIds(): array { { return $this->normalEntityIdList; $allIds = []; foreach ($this->selectedEntityIds as $entityIds) { $allIds = array_merge($allIds, $entityIds); } return $allIds; } public function count(): int { return array_sum( array_map('count', $this->selectedEntityIds) ); } public function isEmpty(): bool { return $this->count() === 0; } } public function isStaleChunkSelected(): bool public function isStaleChunkSelected(): bool { { return $this->count() >= $this->chunkSize; return $this->count() >= $this->chunkSize; } } private function normalisePriority(string|QueuePriorityEnum $priority): string { return $priority instanceof QueuePriorityEnum ? $priority->value : $priority; } } } app/Component/ES/Processor/Traits/SelectEntityListTrait.php +27-4Lines changed: 27 additions & 4 deletions Original file line numberOriginal file lineDiff line numberDiff line change use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; /** /** * Build the correct source list name for the type of entity and priority * Build the correct source list name for the type of entity and priority */ */ trait SelectEntityListTrait trait SelectEntityListTrait { { /** * Highest priority queue for data requiring near-instant availability. * Very few entities should be added here, only when absolutely necessary. */ private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; /** * Normal priority queue for normal application operations. * Almost all update events should pass through this queue */ private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; protected static function selectTargetList(string $entityType, bool $withPriority = false): string /** { * Nonblocking low priority queue. This queue will be consumed only when there is nothing * with higher priority. * * This queue will be used for operations such as es:reset-async */ private const string ENTITIES_LOW_PRIORITIES_LIST = '%s-for-update-low'; protected static function selectTargetList( string $entityType, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { if (! in_array($entityType, UpdateTarget::allowedTargets())) { if (! in_array($entityType, UpdateTarget::allowedTargets())) { throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); } } if ($withPriority) { if ($priority->isHigh()) { Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); } } if ($priority->isLow()) { return sprintf(self::ENTITIES_LOW_PRIORITIES_LIST, $entityType); } return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); } } } } app/Component/ES/Processor/TargetEntitiesSelector.php +26-21Lines changed: 26 additions & 21 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SelectionList; use Jiminny\Component\ES\Processor\DTOs\SelectionList; use Jiminny\Component\ES\Processor\Traits\ExtractIdsTrait; use Jiminny\Component\ES\Processor\Traits\ExtractIdsTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\QueuePriorityEnum; /** /** * This class supplies a list of entities pending an update. * This class supplies a list of entities pending an update. public function select(): SelectionList public function select(): SelectionList { { $staleWorkEntityIds = $this->getStaleChunk(); $selectionList = new SelectionList(); $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $staleWorkEntityIds = $this->getStaleChunk(); if (count($staleWorkEntityIds) > 0) { if (count($staleWorkEntityIds) > 0) { return new SelectionList( /** priorityEntityIdList: $staleWorkEntityIds, * Stale chunks are treated as high priority isStaleChunkSelected: true, */ chunkSize: ChunkSize::getStaleChunkSize($this->updateTarget), $selectionList->markStale(); ); $selectionList->addEntityList(QueuePriorityEnum::HIGH, $staleWorkEntityIds); $selectionList->setChunkSize(ChunkSize::getStaleChunkSize($this->updateTarget)); return $selectionList; } } $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $selectionList->setChunkSize($mainChunkSize); $priorityEntityIdsList = $this->extractIdsFromSet( $priorityEntityIdsList = $this->extractIds(QueuePriorityEnum::HIGH, $mainChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, true), $selectionList->addEntityList(QueuePriorityEnum::HIGH, $priorityEntityIdsList); $mainChunkSize, ); $normalEntityIdsList = []; $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); if ($normalEntityChunkSize > 0) { if ($normalEntityChunkSize > 0) { $normalEntityIdsList = $this->extractIdsFromSet( $normalEntityIdsList = $this->extractIds(QueuePriorityEnum::NORMAL, $normalEntityChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, false), $selectionList->addEntityList(QueuePriorityEnum::NORMAL, $normalEntityIdsList); $normalEntityChunkSize ); } } return new SelectionList( return $selectionList; priorityEntityIdList: $priorityEntityIdsList, normalEntityIdList: $normalEntityIdsList, chunkSize: $mainChunkSize ); } } private function getStaleChunk(): array private function getStaleChunk(): array return []; return []; } } private function extractIds(QueuePriorityEnum $priority, int $chunkSize): array { return $this->extractIdsFromSet( AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, $priority), $chunkSize ); } } } app/Component/ES/AsyncUpdateElasticSearch.php +17-10Lines changed: 17 additions & 10 deletions Original file line numberOriginal file lineDiff line numberDiff line change * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * and other activity related data * and other activity related data */ */ public static function markEntityForUpdate(string $entityType, int $entityId, bool $withPriority = false): void public static function markEntityForUpdate( { string $entityType, $targetList = self::selectTargetList($entityType, $withPriority); int $entityId, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { $targetList = self::selectTargetList($entityType, $priority); Redis::sadd($targetList, $entityId); Redis::sadd($targetList, $entityId); Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ 'entityType' => $entityType, 'entityType' => $entityType, 'entityId' => $entityId, 'entityId' => $entityId, 'collectionKey' => $targetList, 'collectionKey' => $targetList, 'withPriority' => $withPriority, 'priority' => $priority->value, ]); ]); } } public static function bulkMarkEntitiesForUpdate( public static function bulkMarkEntitiesForUpdate( string $entityType, string $entityType, array $entityIds, array $entityIds, bool $withPriority = false QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { ): void { if (empty($entityIds)) { if (empty($entityIds)) { return; return; } } $targetList = self::selectTargetList($entityType, $withPriority); $targetList = self::selectTargetList($entityType, $priority); Redis::saddarray($targetList, $entityIds); Redis::saddarray($targetList, $entityIds); } } * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Takes priority into consideration. * Takes priority into consideration. */ */ public static function getEntitiesSourceList(string $updateTarget, $priority = false): string public static function getEntitiesSourceList( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { return self::selectTargetList($updateTarget, $priority); return self::selectTargetList($updateTarget, $priority); } } /** /** * Externally called helper methods * Externally called helper methods * - count and flush * - count and flush */ */ public static function getEntitiesListCount(string $updateTarget, $priority = false): int public static function getEntitiesListCount( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): int { $targetList = self::selectTargetList($updateTarget, $priority); $targetList = self::selectTargetList($updateTarget, $priority); return Redis::scard($targetList); return Redis::scard($targetList); app/Component/ES/QueuePriorityEnum.php +40Lines changed: 40 additions & 0 deletions Original file line numberOriginal file lineDiff line numberDiff line change <?php declare(strict_types=1); namespace Jiminny\Component\ES; use Jiminny\Exceptions\InvalidArgumentException; enum QueuePriorityEnum: string { case HIGH = 'high'; case NORMAL = 'normal'; case LOW = 'low'; public static function tryFromString(string $value): self { if (! self::isValid($value)) { throw new InvalidArgumentException( sprintf('Invalid queue priority "%s" selected', $value) ); } return self::tryFrom($value); } public static function isValid(string $value): bool { return self::tryFrom($value) !== null; } public function isLow(): bool { return $this === self::LOW; } public function isHigh(): bool { return $this === self::HIGH; } } app/Component/ES/UpdateProcessManager.php +12-9Lines changed: 12 additions & 9 deletions Original file line numberOriginal file lineDiff line numberDiff line change if ($selectionList->isEmpty()) { if ($selectionList->isEmpty()) { return false; return false; } } /** /** * A stale chunk will always be smaller than a regular chunk. * A stale chunk will always be smaller than a regular chunk. * That doesn't mean there aren't any other scheduled entities for processing * That doesn't mean there aren't any other scheduled entities for processing private function rescheduleThrottledEntities(SelectionList $selectionList): void private function rescheduleThrottledEntities(SelectionList $selectionList): void { { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $groups = $selectionList->getEntityListGroups(); $this->updateTarget, foreach ($groups as $eachGroup) { $selectionList->getNormalPriorityEntityId() $groupEntityIds = $selectionList->getEntityListItemsByGroup($eachGroup); ); if (! empty($groupEntityIds)) { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $this->updateTarget, entityType: $this->updateTarget, $selectionList->getHighPriorityEntityIds(), entityIds: $groupEntityIds, true priority: QueuePriorityEnum::tryFromString($eachGroup) ); ); } } } } } } app/Console/Commands/Elasticsearch/AsyncUpdateEsEntities.php +9-3Lines changed: 9 additions & 3 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Illuminate\Support\Str; use Illuminate\Support\Str; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Component\ES\UpdateProcessManager; use Jiminny\Component\ES\UpdateProcessManager; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Traits\GracefullyStoppable; use Jiminny\Traits\GracefullyStoppable; Redis::set($gaugeLockName, true); Redis::set($gaugeLockName, true); Redis::expire($gaugeLockName, 60); Redis::expire($gaugeLockName, 60); $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::HIGH), ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update', $updateTarget), stat: sprintf('jiminny.%s-for-update', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::NORMAL), ); ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), stat: sprintf('jiminny.%s-for-update-low', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, true), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::LOW), ); ); } } app/Console/Commands/Elasticsearch/ResetAsyncElasticSearchCommand.php +5-1Lines changed: 5 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\Traits\ValidateUpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\ValidateUpdateTargetTrait; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Component\ES\Repositories\EsResetRepositoryInterface; use Jiminny\Component\ES\Repositories\EsResetRepositoryInterface; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Traits\GracefullyStoppable; use Jiminny\Traits\GracefullyStoppable; private function getRemainingScheduledEntities(bool $printStatus = false): int private function getRemainingScheduledEntities(bool $printStatus = false): int { { $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget, true); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount( $this->updateTarget, QueuePriorityEnum::HIGH ); if ($printStatus) { if ($printStatus) { $this->line( $this->line(
You said
app/Component/ES/Listeners/UpdateMultipleTargetsListener.php
+2-1Lines changed: 2 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\Component\ES\Listeners;
namespace Jiminny\Component\ES\Listeners;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\QueuePriorityEnum;
use Jiminny\Contracts\ES\Events\UpdateMultipleEntities;
use Jiminny\Contracts\ES\Events\UpdateMultipleEntities;
use Psr\Log\LoggerInterface;
use Psr\Log\LoggerInterface;
AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(
AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(
$event->getUpdateTargetValue(),
$event->getUpdateTargetValue(),
$event->getEntities(),
$event->getEntities(),
$event->isPriority()
$event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL,
);
);
}
}
}
}
app/Component/ES/Listeners/UpdateSingleTargetListener.php
+9-1Lines changed: 9 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Actions\TrackElasticSearchOperations;
use Jiminny\Component\ES\Actions\TrackElasticSearchOperations;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\Processor\EntityQueryBuilder;
use Jiminny\Component\ES\Processor\EntityQueryBuilder;
use Jiminny\Component\ES\QueuePriorityEnum;
use Jiminny\Contracts\ES\Events\UpdateSingleEntity;
use Jiminny\Contracts\ES\Events\UpdateSingleEntity;
use Psr\Log\LoggerInterface;
use Psr\Log\LoggerInterface;
'entityId' => $event->getEntityId(),
'entityId' => $event->getEntityId(),
]);
]);
/**
* @important:
* Synchronous event should eventually be deprecated.
* Instant write operations are blocking and should be used sparingly.
* It is much better in terms of performance to write 100 or 1000 documents at once,
* and have one blocking reindex operation, instead of writing 10 documents synchronously.
*/
if ($event->isSyncEvent()) {
if ($event->isSyncEvent()) {
$this->handleSyncEvent($event);
$this->handleSyncEvent($event);
AsyncUpdateElasticSearch::markEntityForUpdate(
AsyncUpdateElasticSearch::markEntityForUpdate(
$event->getUpdateTargetValue(),
$event->getUpdateTargetValue(),
$event->getEntityId(),
$event->getEntityId(),
$event->isPriority()
$event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL,
);
);
}
}
app/Component/ES/Processor/Actions/UpsertDocumentsAction.php
+2-1Lines changed: 2 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SimpleCollection;
use Jiminny\Component\ES\Processor\DTOs\SimpleCollection;
use Jiminny\Component\ES\Processor\ResponseEvaluator;
use Jiminny\Component\ES\Processor\ResponseEvaluator;
use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait;
use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait;
use Jiminny\Component\ES\QueuePriorityEnum;
use Jiminny\Exceptions\InvalidDataException;
use Jiminny\Exceptions\InvalidDataException;
use Sentry\Laravel\Facade as Sentry;
use Sentry\Laravel\Facade as Sentry;
AsyncUpdateElasticSearch::markEntityForUpdate(
AsyncUpdateElasticSearch::markEntityForUpdate(
entityType: $this->updateTarget,
entityType: $this->updateTarget,
entityId: (int) $document->getId(),
entityId: (int) $document->getId(),
withPriority: true
priority: QueuePriorityEnum::HIGH,
);
);
}
}
app/Component/ES/Processor/DTOs/SelectionList.php
+54-17Lines changed: 54 additions & 17 deletions
Original file line numberOriginal file lineDiff line numberDiff line change
namespace Jiminny\Component\ES\Processor\DTOs;
namespace Jiminny\Component\ES\Processor\DTOs;
use Jiminny\Component\ES\QueuePriorityEnum;
/**
/**
* A very basic and simple collection of entity IDs.
* A very basic and simple collection of entity IDs.
*/
*/
class SelectionList
class SelectionList
{
{
public function __construct(
private const int DEFAULT_CHUNK = 200;
private readonly array $priorityEntityIdList = [],
private readonly array $normalEntityIdList = [],
private int $chunkSize = self::DEFAULT_CHUNK;
private readonly bool $isStaleChunkSelected = false,
private bool $isStaleChunkSelected = false;
private readonly int $chunkSize = 200,
private array $selectedEntityIds = [];
) {
// Do nothing
public function setChunkSize(int $chunkSize): void
{
$this->chunkSize = $chunkSize;
}
}
public function getAllIds(): array
public function markStale(): void
{
{
return array_merge($this->priorityEntityIdList, $this->normalEntityIdList);
$this->isStaleChunkSelected = true;
}
}
public function count(): int
public function addEntityList(string|QueuePriorityEnum $priority, array $entityIds): void
{
{
return count($this->priorityEntityIdList) + count($this->normalEntityIdList);
$priorityKey = $this->normalisePriority($priority);
if (! array_key_exists($priorityKey, $this->selectedEntityIds)) {
$this->selectedEntityIds[$priorityKey] = [];
}
$this->selectedEntityIds[$priorityKey] = array_merge($this->selectedEntityIds[$priorityKey], $entityIds);
}
}
public function isEmpty(): bool
/**
* @return string[]
*/
public function getEntityListGroups(): array
{
{
return empty($this->priorityEntityIdList) && empty($this->normalEntityIdList);
return array_keys($this->selectedEntityIds);
}
}
public function getHighPriorityEntityIds(): array
public function getEntityListItemsByGroup(string|QueuePriorityEnum $priority): array
{
{
return $this->priorityEntityIdList;
$priorityKey = $this->normalisePriority($priority);
return $this->selectedEntityIds[$priorityKey] ?? [];
}
}
public function getNormalPriorityEntityId(): array
public function getAllIds(): array
{
{
return $this->normalEntityIdList;
$allIds = [];
foreach ($this->selectedEntityIds as $entityIds) {
$allIds = array_merge($allIds, $entityIds);
}
return $allIds;
}
public function count(): int
{
return array_sum(
array_map('count', $this->selectedEntityIds)
);
}
public function isEmpty(): bool
{
return $this->count() === 0;
}
}...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
55705
|
1934
|
3
|
2026-05-19T06:43:41.033541+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779173021033_m1.jpg...
|
Firefox
|
JY-20808 low priority indexing queue by Vasil-Jimi JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app — Work...
|
1
|
github.com/jiminny/app/pull/12082/changes#diff-616 github.com/jiminny/app/pull/12082/changes#diff-61654edeebd72388bddd97cafcac889a2d106f54bb484a719d4067878bb9b011...
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
Close tab
New Tab
Customize sidebar
Close Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
AI Chat settings
Close
WORK, Google Account: [EMAIL]
Main menu
New chat
Gemini
New Chat
Open menu for conversation actions.
Conversation with Gemini
Conversation with Gemini
Show the uploaded image in a lightbox
Copy prompt
You said Make a PR of changes Find potential issues and bottlenecks
You said
Make a PR of changes Find potential issues and bottlenecks
Listen
Show thinking
Gemini said
Gemini said
I can see you've uploaded a screenshot of a code diff, likely from a version control system given the red and green highlights. I would love to help you review the changes, spot bottlenecks, and help you draft a Pull Request.
However,
the image resolution is far too low for me to read.
It appears to be a completely zoomed-out view where the code has been reduced to tiny, illegible pixels. Because of this, I cannot extract any text or logic to analyze.
How You Can Share the Code
How You Can Share the Code
To help me review your code effectively, please try one of the following:
Paste the text directly:
Copy the specific code blocks (both the old and new versions if possible) and paste them directly into our chat.
Upload the files:
If the changes are extensive, you can upload the raw text or code files.
Take high-resolution screenshots:
If you must use images, take closer, readable screenshots of the specific functions or methods you want me to review.
Once you provide the readable code, I can dive right in to identify potential bugs, assess performance bottlenecks, and help you summarize the changes for your PR!
Good response
Bad response
Share & export
Copy
Show more options
Copy prompt
Edit
You said app/Component/ES/Listeners/UpdateMultipleTargetsListener.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\Component\ES\Listeners; namespace Jiminny\Component\ES\Listeners; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Contracts\ES\Events\UpdateMultipleEntities; use Jiminny\Contracts\ES\Events\UpdateMultipleEntities; use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface; AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntities(), $event->getEntities(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } } } app/Component/ES/Listeners/UpdateSingleTargetListener.php +9-1Lines changed: 9 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Actions\TrackElasticSearchOperations; use Jiminny\Component\ES\Actions\TrackElasticSearchOperations; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Contracts\ES\Events\UpdateSingleEntity; use Jiminny\Contracts\ES\Events\UpdateSingleEntity; use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface; 'entityId' => $event->getEntityId(), 'entityId' => $event->getEntityId(), ]); ]); /** * @important: * Synchronous event should eventually be deprecated. * Instant write operations are blocking and should be used sparingly. * It is much better in terms of performance to write 100 or 1000 documents at once, * and have one blocking reindex operation, instead of writing 10 documents synchronously. */ if ($event->isSyncEvent()) { if ($event->isSyncEvent()) { $this->handleSyncEvent($event); $this->handleSyncEvent($event); AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntityId(), $event->getEntityId(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } app/Component/ES/Processor/Actions/UpsertDocumentsAction.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SimpleCollection; use Jiminny\Component\ES\Processor\DTOs\SimpleCollection; use Jiminny\Component\ES\Processor\ResponseEvaluator; use Jiminny\Component\ES\Processor\ResponseEvaluator; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Exceptions\InvalidDataException; use Jiminny\Exceptions\InvalidDataException; use Sentry\Laravel\Facade as Sentry; use Sentry\Laravel\Facade as Sentry; AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( entityType: $this->updateTarget, entityType: $this->updateTarget, entityId: (int) $document->getId(), entityId: (int) $document->getId(), withPriority: true priority: QueuePriorityEnum::HIGH, ); ); } } app/Component/ES/Processor/DTOs/SelectionList.php +54-17Lines changed: 54 additions & 17 deletions Original file line numberOriginal file lineDiff line numberDiff line change namespace Jiminny\Component\ES\Processor\DTOs; namespace Jiminny\Component\ES\Processor\DTOs; use Jiminny\Component\ES\QueuePriorityEnum; /** /** * A very basic and simple collection of entity IDs. * A very basic and simple collection of entity IDs. */ */ class SelectionList class SelectionList { { public function __construct( private const int DEFAULT_CHUNK = 200; private readonly array $priorityEntityIdList = [], private readonly array $normalEntityIdList = [], private int $chunkSize = self::DEFAULT_CHUNK; private readonly bool $isStaleChunkSelected = false, private bool $isStaleChunkSelected = false; private readonly int $chunkSize = 200, private array $selectedEntityIds = []; ) { // Do nothing public function setChunkSize(int $chunkSize): void { $this->chunkSize = $chunkSize; } } public function getAllIds(): array public function markStale(): void { { return array_merge($this->priorityEntityIdList, $this->normalEntityIdList); $this->isStaleChunkSelected = true; } } public function count(): int public function addEntityList(string|QueuePriorityEnum $priority, array $entityIds): void { { return count($this->priorityEntityIdList) + count($this->normalEntityIdList); $priorityKey = $this->normalisePriority($priority); if (! array_key_exists($priorityKey, $this->selectedEntityIds)) { $this->selectedEntityIds[$priorityKey] = []; } $this->selectedEntityIds[$priorityKey] = array_merge($this->selectedEntityIds[$priorityKey], $entityIds); } } public function isEmpty(): bool /** * @return string[] */ public function getEntityListGroups(): array { { return empty($this->priorityEntityIdList) && empty($this->normalEntityIdList); return array_keys($this->selectedEntityIds); } } public function getHighPriorityEntityIds(): array public function getEntityListItemsByGroup(string|QueuePriorityEnum $priority): array { { return $this->priorityEntityIdList; $priorityKey = $this->normalisePriority($priority); return $this->selectedEntityIds[$priorityKey] ?? []; } } public function getNormalPriorityEntityId(): array public function getAllIds(): array { { return $this->normalEntityIdList; $allIds = []; foreach ($this->selectedEntityIds as $entityIds) { $allIds = array_merge($allIds, $entityIds); } return $allIds; } public function count(): int { return array_sum( array_map('count', $this->selectedEntityIds) ); } public function isEmpty(): bool { return $this->count() === 0; } } public function isStaleChunkSelected(): bool public function isStaleChunkSelected(): bool { { return $this->count() >= $this->chunkSize; return $this->count() >= $this->chunkSize; } } private function normalisePriority(string|QueuePriorityEnum $priority): string { return $priority instanceof QueuePriorityEnum ? $priority->value : $priority; } } } app/Component/ES/Processor/Traits/SelectEntityListTrait.php +27-4Lines changed: 27 additions & 4 deletions Original file line numberOriginal file lineDiff line numberDiff line change use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; /** /** * Build the correct source list name for the type of entity and priority * Build the correct source list name for the type of entity and priority */ */ trait SelectEntityListTrait trait SelectEntityListTrait { { /** * Highest priority queue for data requiring near-instant availability. * Very few entities should be added here, only when absolutely necessary. */ private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; /** * Normal priority queue for normal application operations. * Almost all update events should pass through this queue */ private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; protected static function selectTargetList(string $entityType, bool $withPriority = false): string /** { * Nonblocking low priority queue. This queue will be consumed only when there is nothing * with higher priority. * * This queue will be used for operations such as es:reset-async */ private const string ENTITIES_LOW_PRIORITIES_LIST = '%s-for-update-low'; protected static function selectTargetList( string $entityType, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { if (! in_array($entityType, UpdateTarget::allowedTargets())) { if (! in_array($entityType, UpdateTarget::allowedTargets())) { throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); } } if ($withPriority) { if ($priority->isHigh()) { Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); } } if ($priority->isLow()) { return sprintf(self::ENTITIES_LOW_PRIORITIES_LIST, $entityType); } return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); } } } } app/Component/ES/Processor/TargetEntitiesSelector.php +26-21Lines changed: 26 additions & 21 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SelectionList; use Jiminny\Component\ES\Processor\DTOs\SelectionList; use Jiminny\Component\ES\Processor\Traits\ExtractIdsTrait; use Jiminny\Component\ES\Processor\Traits\ExtractIdsTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\QueuePriorityEnum; /** /** * This class supplies a list of entities pending an update. * This class supplies a list of entities pending an update. public function select(): SelectionList public function select(): SelectionList { { $staleWorkEntityIds = $this->getStaleChunk(); $selectionList = new SelectionList(); $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $staleWorkEntityIds = $this->getStaleChunk(); if (count($staleWorkEntityIds) > 0) { if (count($staleWorkEntityIds) > 0) { return new SelectionList( /** priorityEntityIdList: $staleWorkEntityIds, * Stale chunks are treated as high priority isStaleChunkSelected: true, */ chunkSize: ChunkSize::getStaleChunkSize($this->updateTarget), $selectionList->markStale(); ); $selectionList->addEntityList(QueuePriorityEnum::HIGH, $staleWorkEntityIds); $selectionList->setChunkSize(ChunkSize::getStaleChunkSize($this->updateTarget)); return $selectionList; } } $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $selectionList->setChunkSize($mainChunkSize); $priorityEntityIdsList = $this->extractIdsFromSet( $priorityEntityIdsList = $this->extractIds(QueuePriorityEnum::HIGH, $mainChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, true), $selectionList->addEntityList(QueuePriorityEnum::HIGH, $priorityEntityIdsList); $mainChunkSize, ); $normalEntityIdsList = []; $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); if ($normalEntityChunkSize > 0) { if ($normalEntityChunkSize > 0) { $normalEntityIdsList = $this->extractIdsFromSet( $normalEntityIdsList = $this->extractIds(QueuePriorityEnum::NORMAL, $normalEntityChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, false), $selectionList->addEntityList(QueuePriorityEnum::NORMAL, $normalEntityIdsList); $normalEntityChunkSize ); } } return new SelectionList( return $selectionList; priorityEntityIdList: $priorityEntityIdsList, normalEntityIdList: $normalEntityIdsList, chunkSize: $mainChunkSize ); } } private function getStaleChunk(): array private function getStaleChunk(): array return []; return []; } } private function extractIds(QueuePriorityEnum $priority, int $chunkSize): array { return $this->extractIdsFromSet( AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, $priority), $chunkSize ); } } } app/Component/ES/AsyncUpdateElasticSearch.php +17-10Lines changed: 17 additions & 10 deletions Original file line numberOriginal file lineDiff line numberDiff line change * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * and other activity related data * and other activity related data */ */ public static function markEntityForUpdate(string $entityType, int $entityId, bool $withPriority = false): void public static function markEntityForUpdate( { string $entityType, $targetList = self::selectTargetList($entityType, $withPriority); int $entityId, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { $targetList = self::selectTargetList($entityType, $priority); Redis::sadd($targetList, $entityId); Redis::sadd($targetList, $entityId); Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ 'entityType' => $entityType, 'entityType' => $entityType, 'entityId' => $entityId, 'entityId' => $entityId, 'collectionKey' => $targetList, 'collectionKey' => $targetList, 'withPriority' => $withPriority, 'priority' => $priority->value, ]); ]); } } public static function bulkMarkEntitiesForUpdate( public static function bulkMarkEntitiesForUpdate( string $entityType, string $entityType, array $entityIds, array $entityIds, bool $withPriority = false QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { ): void { if (empty($entityIds)) { if (empty($entityIds)) { return; return; } } $targetList = self::selectTargetList($entityType, $withPriority); $targetList = self::selectTargetList($entityType, $priority); Redis::saddarray($targetList, $entityIds); Redis::saddarray($targetList, $entityIds); } } * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Takes priority into consideration. * Takes priority into consideration. */ */ public static function getEntitiesSourceList(string $updateTarget, $priority = false): string public static function getEntitiesSourceList( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { return self::selectTargetList($updateTarget, $priority); return self::selectTargetList($updateTarget, $priority); } } /** /** * Externally called helper methods * Externally called helper methods * - count and flush * - count and flush */ */ public static function getEntitiesListCount(string $updateTarget, $priority = false): int public static function getEntitiesListCount( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): int { $targetList = self::selectTargetList($updateTarget, $priority); $targetList = self::selectTargetList($updateTarget, $priority); return Redis::scard($targetList); return Redis::scard($targetList); app/Component/ES/QueuePriorityEnum.php +40Lines changed: 40 additions & 0 deletions Original file line numberOriginal file lineDiff line numberDiff line change <?php declare(strict_types=1); namespace Jiminny\Component\ES; use Jiminny\Exceptions\InvalidArgumentException; enum QueuePriorityEnum: string { case HIGH = 'high'; case NORMAL = 'normal'; case LOW = 'low'; public static function tryFromString(string $value): self { if (! self::isValid($value)) { throw new InvalidArgumentException( sprintf('Invalid queue priority "%s" selected', $value) ); } return self::tryFrom($value); } public static function isValid(string $value): bool { return self::tryFrom($value) !== null; } public function isLow(): bool { return $this === self::LOW; } public function isHigh(): bool { return $this === self::HIGH; } } app/Component/ES/UpdateProcessManager.php +12-9Lines changed: 12 additions & 9 deletions Original file line numberOriginal file lineDiff line numberDiff line change if ($selectionList->isEmpty()) { if ($selectionList->isEmpty()) { return false; return false; } } /** /** * A stale chunk will always be smaller than a regular chunk. * A stale chunk will always be smaller than a regular chunk. * That doesn't mean there aren't any other scheduled entities for processing * That doesn't mean there aren't any other scheduled entities for processing private function rescheduleThrottledEntities(SelectionList $selectionList): void private function rescheduleThrottledEntities(SelectionList $selectionList): void { { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $groups = $selectionList->getEntityListGroups(); $this->updateTarget, foreach ($groups as $eachGroup) { $selectionList->getNormalPriorityEntityId() $groupEntityIds = $selectionList->getEntityListItemsByGroup($eachGroup); ); if (! empty($groupEntityIds)) { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $this->updateTarget, entityType: $this->updateTarget, $selectionList->getHighPriorityEntityIds(), entityIds: $groupEntityIds, true priority: QueuePriorityEnum::tryFromString($eachGroup) ); ); } } } } } } app/Console/Commands/Elasticsearch/AsyncUpdateEsEntities.php +9-3Lines changed: 9 additions & 3 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Illuminate\Support\Str; use Illuminate\Support\Str; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Component\ES\UpdateProcessManager; use Jiminny\Component\ES\UpdateProcessManager; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Traits\GracefullyStoppable; use Jiminny\Traits\GracefullyStoppable; Redis::set($gaugeLockName, true); Redis::set($gaugeLockName, true); Redis::expire($gaugeLockName, 60); Redis::expire($gaugeLockName, 60); $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::HIGH), ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update', $updateTarget), stat: sprintf('jiminny.%s-for-update', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::NORMAL), ); ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), stat: sprintf('jiminny.%s-for-update-low', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, true), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::LOW), ); ); } } app/Console/Commands/Elasticsearch/ResetAsyncElasticSearchCommand.php +5-1Lines changed: 5 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\Traits\ValidateUpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\ValidateUpdateTargetTrait; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Component\ES\Repositories\EsResetRepositoryInterface; use Jiminny\Component\ES\Repositories\EsResetRepositoryInterface; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Traits\GracefullyStoppable; use Jiminny\Traits\GracefullyStoppable; private function getRemainingScheduledEntities(bool $printStatus = false): int private function getRemainingScheduledEntities(bool $printStatus = false): int { { $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget, true); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount( $this->updateTarget, QueuePriorityEnum::HIGH ); if ($printStatus) { if ($printStatus) { $this->line( $this->line(
You said
app/Component/ES/Listeners/UpdateMultipleTargetsListener.php
+2-1Lines changed: 2 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\Component\ES\Listeners;
namespace Jiminny\Component\ES\Listeners;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\QueuePriorityEnum;
use Jiminny\Contracts\ES\Events\UpdateMultipleEntities;
use Jiminny\Contracts\ES\Events\UpdateMultipleEntities;
use Psr\Log\LoggerInterface;
use Psr\Log\LoggerInterface;
AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(
AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(
$event->getUpdateTargetValue(),
$event->getUpdateTargetValue(),
$event->getEntities(),
$event->getEntities(),
$event->isPriority()
$event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL,
);
);
}
}
}
}
app/Component/ES/Listeners/UpdateSingleTargetListener.php
+9-1Lines changed: 9 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Actions\TrackElasticSearchOperations;
use Jiminny\Component\ES\Actions\TrackElasticSearchOperations;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\Processor\EntityQueryBuilder;
use Jiminny\Component\ES\Processor\EntityQueryBuilder;
use Jiminny\Component\ES\QueuePriorityEnum;
use Jiminny\Contracts\ES\Events\UpdateSingleEntity;
use Jiminny\Contracts\ES\Events\UpdateSingleEntity;
use Psr\Log\LoggerInterface;
use Psr\Log\LoggerInterface;
'entityId' => $event->getEntityId(),
'entityId' => $event->getEntityId(),
]);
]);
/**
* @important:
* Synchronous event should eventually be deprecated.
* Instant write operations are blocking and should be used sparingly.
* It is much better in terms of performance to write 100 or 1000 documents at once,
* and have one blocking reindex operation, instead of writing 10 documents synchronously.
*/
if ($event->isSyncEvent()) {
if ($event->isSyncEvent()) {
$this->handleSyncEvent($event);
$this->handleSyncEvent($event);
AsyncUpdateElasticSearch::markEntityForUpdate(
AsyncUpdateElasticSearch::markEntityForUpdate(
$event->getUpdateTargetValue(),
$event->getUpdateTargetValue(),
$event->getEntityId(),
$event->getEntityId(),
$event->isPriority()
$event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL,
);
);
}
}
app/Component/ES/Processor/Actions/UpsertDocumentsAction.php
+2-1Lines changed: 2 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SimpleCollection;
use Jiminny\Component\ES\Processor\DTOs\SimpleCollection;
use Jiminny\Component\ES\Processor\ResponseEvaluator;
use Jiminny\Component\ES\Processor\ResponseEvaluator;
use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait;
use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait;
use Jiminny\Component\ES\QueuePriorityEnum;
use Jiminny\Exceptions\InvalidDataException;
use Jiminny\Exceptions\InvalidDataException;
use Sentry\Laravel\Facade as Sentry;
use Sentry\Laravel\Facade as Sentry;
AsyncUpdateElasticSearch::markEntityForUpdate(
AsyncUpdateElasticSearch::markEntityForUpdate(
entityType: $this->updateTarget,
entityType: $this->updateTarget,
entityId: (int) $document->getId(),
entityId: (int) $document->getId(),
withPriority: true
priority: QueuePriorityEnum::HIGH,
);
);
}
}
app/Component/ES/Processor/DTOs/SelectionList.php
+54-17Lines changed: 54 additions & 17 deletions
Original file line numberOriginal file lineDiff line numberDiff line change
namespace Jiminny\Component\ES\Processor\DTOs;
namespace Jiminny\Component\ES\Processor\DTOs;
use Jiminny\Component\ES\QueuePriorityEnum;
/**
/**
* A very basic and simple collection of entity IDs.
* A very basic and simple collection of entity IDs.
*/
*/
class SelectionList
class SelectionList
{
{
public function __construct(
private const int DEFAULT_CHUNK = 200;
private readonly array $priorityEntityIdList = [],
private readonly array $normalEntityIdList = [],
private int $chunkSize = self::DEFAULT_CHUNK;
private readonly bool $isStaleChunkSelected = false,
private bool $isStaleChunkSelected = false;
private readonly int $chunkSize = 200,
private array $selectedEntityIds = [];
) {
// Do nothing
public function setChunkSize(int $chunkSize): void
{
$this->chunkSize = $chunkSize;
}
}
public function getAllIds(): array
public function markStale(): void
{
{
return array_merge($this->priorityEntityIdList, $this->normalEntityIdList);
$this->isStaleChunkSelected = true;
}
}...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New Tab","depth":4,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Close Google Gemini (⌃X)","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Tabs from other devices","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"AI Chat settings","depth":7,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Close","depth":7,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"WORK, Google Account: lukas.kovalik@jiminny.com","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Main menu","depth":12,"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New chat","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Gemini","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"New Chat","depth":12,"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Open menu for conversation actions.","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXHeading","text":"Conversation with Gemini","depth":15,"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Conversation with Gemini","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Show the uploaded image in a lightbox","depth":21,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy prompt","depth":21,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"You said Make a PR of changes Find potential issues and bottlenecks","depth":21,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"You said","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Make a PR of changes Find potential issues and bottlenecks","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Listen","depth":22,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Show thinking","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Gemini said","depth":20,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Gemini said","depth":21,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"I can see you've uploaded a screenshot of a code diff, likely from a version control system given the red and green highlights. I would love to help you review the changes, spot bottlenecks, and help you draft a Pull Request.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"However,","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"the image resolution is far too low for me to read.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"It appears to be a completely zoomed-out view where the code has been reduced to tiny, illegible pixels. Because of this, I cannot extract any text or logic to analyze.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"How You Can Share the Code","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"How You Can Share the Code","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"To help me review your code effectively, please try one of the following:","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Paste the text directly:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Copy the specific code blocks (both the old and new versions if possible) and paste them directly into our chat.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Upload the files:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"If the changes are extensive, you can upload the raw text or code files.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Take high-resolution screenshots:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"If you must use images, take closer, readable screenshots of the specific functions or methods you want me to review.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Once you provide the readable code, I can dive right in to identify potential bugs, assess performance bottlenecks, and help you summarize the changes for your PR!","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Good response","depth":22,"on_screen":false,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Bad response","depth":22,"on_screen":false,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Share & export","depth":21,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy","depth":22,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Show more options","depth":21,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy prompt","depth":21,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Edit","depth":21,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"You said app/Component/ES/Listeners/UpdateMultipleTargetsListener.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\\Component\\ES\\Listeners; namespace Jiminny\\Component\\ES\\Listeners; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Contracts\\ES\\Events\\UpdateMultipleEntities; use Jiminny\\Contracts\\ES\\Events\\UpdateMultipleEntities; use Psr\\Log\\LoggerInterface; use Psr\\Log\\LoggerInterface; AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntities(), $event->getEntities(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } } } app/Component/ES/Listeners/UpdateSingleTargetListener.php +9-1Lines changed: 9 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Actions\\TrackElasticSearchOperations; use Jiminny\\Component\\ES\\Actions\\TrackElasticSearchOperations; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder; use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Contracts\\ES\\Events\\UpdateSingleEntity; use Jiminny\\Contracts\\ES\\Events\\UpdateSingleEntity; use Psr\\Log\\LoggerInterface; use Psr\\Log\\LoggerInterface; 'entityId' => $event->getEntityId(), 'entityId' => $event->getEntityId(), ]); ]); /** * @important: * Synchronous event should eventually be deprecated. * Instant write operations are blocking and should be used sparingly. * It is much better in terms of performance to write 100 or 1000 documents at once, * and have one blocking reindex operation, instead of writing 10 documents synchronously. */ if ($event->isSyncEvent()) { if ($event->isSyncEvent()) { $this->handleSyncEvent($event); $this->handleSyncEvent($event); AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntityId(), $event->getEntityId(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } app/Component/ES/Processor/Actions/UpsertDocumentsAction.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Processor\\DTOs\\SimpleCollection; use Jiminny\\Component\\ES\\Processor\\DTOs\\SimpleCollection; use Jiminny\\Component\\ES\\Processor\\ResponseEvaluator; use Jiminny\\Component\\ES\\Processor\\ResponseEvaluator; use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait; use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Exceptions\\InvalidDataException; use Jiminny\\Exceptions\\InvalidDataException; use Sentry\\Laravel\\Facade as Sentry; use Sentry\\Laravel\\Facade as Sentry; AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( entityType: $this->updateTarget, entityType: $this->updateTarget, entityId: (int) $document->getId(), entityId: (int) $document->getId(), withPriority: true priority: QueuePriorityEnum::HIGH, ); ); } } app/Component/ES/Processor/DTOs/SelectionList.php +54-17Lines changed: 54 additions & 17 deletions Original file line numberOriginal file lineDiff line numberDiff line change namespace Jiminny\\Component\\ES\\Processor\\DTOs; namespace Jiminny\\Component\\ES\\Processor\\DTOs; use Jiminny\\Component\\ES\\QueuePriorityEnum; /** /** * A very basic and simple collection of entity IDs. * A very basic and simple collection of entity IDs. */ */ class SelectionList class SelectionList { { public function __construct( private const int DEFAULT_CHUNK = 200; private readonly array $priorityEntityIdList = [], private readonly array $normalEntityIdList = [], private int $chunkSize = self::DEFAULT_CHUNK; private readonly bool $isStaleChunkSelected = false, private bool $isStaleChunkSelected = false; private readonly int $chunkSize = 200, private array $selectedEntityIds = []; ) { // Do nothing public function setChunkSize(int $chunkSize): void { $this->chunkSize = $chunkSize; } } public function getAllIds(): array public function markStale(): void { { return array_merge($this->priorityEntityIdList, $this->normalEntityIdList); $this->isStaleChunkSelected = true; } } public function count(): int public function addEntityList(string|QueuePriorityEnum $priority, array $entityIds): void { { return count($this->priorityEntityIdList) + count($this->normalEntityIdList); $priorityKey = $this->normalisePriority($priority); if (! array_key_exists($priorityKey, $this->selectedEntityIds)) { $this->selectedEntityIds[$priorityKey] = []; } $this->selectedEntityIds[$priorityKey] = array_merge($this->selectedEntityIds[$priorityKey], $entityIds); } } public function isEmpty(): bool /** * @return string[] */ public function getEntityListGroups(): array { { return empty($this->priorityEntityIdList) && empty($this->normalEntityIdList); return array_keys($this->selectedEntityIds); } } public function getHighPriorityEntityIds(): array public function getEntityListItemsByGroup(string|QueuePriorityEnum $priority): array { { return $this->priorityEntityIdList; $priorityKey = $this->normalisePriority($priority); return $this->selectedEntityIds[$priorityKey] ?? []; } } public function getNormalPriorityEntityId(): array public function getAllIds(): array { { return $this->normalEntityIdList; $allIds = []; foreach ($this->selectedEntityIds as $entityIds) { $allIds = array_merge($allIds, $entityIds); } return $allIds; } public function count(): int { return array_sum( array_map('count', $this->selectedEntityIds) ); } public function isEmpty(): bool { return $this->count() === 0; } } public function isStaleChunkSelected(): bool public function isStaleChunkSelected(): bool { { return $this->count() >= $this->chunkSize; return $this->count() >= $this->chunkSize; } } private function normalisePriority(string|QueuePriorityEnum $priority): string { return $priority instanceof QueuePriorityEnum ? $priority->value : $priority; } } } app/Component/ES/Processor/Traits/SelectEntityListTrait.php +27-4Lines changed: 27 additions & 4 deletions Original file line numberOriginal file lineDiff line numberDiff line change use Illuminate\\Support\\Facades\\Log; use Illuminate\\Support\\Facades\\Log; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Exceptions\\InvalidArgumentException; use Jiminny\\Exceptions\\InvalidArgumentException; /** /** * Build the correct source list name for the type of entity and priority * Build the correct source list name for the type of entity and priority */ */ trait SelectEntityListTrait trait SelectEntityListTrait { { /** * Highest priority queue for data requiring near-instant availability. * Very few entities should be added here, only when absolutely necessary. */ private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; /** * Normal priority queue for normal application operations. * Almost all update events should pass through this queue */ private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; protected static function selectTargetList(string $entityType, bool $withPriority = false): string /** { * Nonblocking low priority queue. This queue will be consumed only when there is nothing * with higher priority. * * This queue will be used for operations such as es:reset-async */ private const string ENTITIES_LOW_PRIORITIES_LIST = '%s-for-update-low'; protected static function selectTargetList( string $entityType, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { if (! in_array($entityType, UpdateTarget::allowedTargets())) { if (! in_array($entityType, UpdateTarget::allowedTargets())) { throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); } } if ($withPriority) { if ($priority->isHigh()) { Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); } } if ($priority->isLow()) { return sprintf(self::ENTITIES_LOW_PRIORITIES_LIST, $entityType); } return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); } } } } app/Component/ES/Processor/TargetEntitiesSelector.php +26-21Lines changed: 26 additions & 21 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Processor\\DTOs\\SelectionList; use Jiminny\\Component\\ES\\Processor\\DTOs\\SelectionList; use Jiminny\\Component\\ES\\Processor\\Traits\\ExtractIdsTrait; use Jiminny\\Component\\ES\\Processor\\Traits\\ExtractIdsTrait; use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait; use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait; use Jiminny\\Component\\ES\\QueuePriorityEnum; /** /** * This class supplies a list of entities pending an update. * This class supplies a list of entities pending an update. public function select(): SelectionList public function select(): SelectionList { { $staleWorkEntityIds = $this->getStaleChunk(); $selectionList = new SelectionList(); $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $staleWorkEntityIds = $this->getStaleChunk(); if (count($staleWorkEntityIds) > 0) { if (count($staleWorkEntityIds) > 0) { return new SelectionList( /** priorityEntityIdList: $staleWorkEntityIds, * Stale chunks are treated as high priority isStaleChunkSelected: true, */ chunkSize: ChunkSize::getStaleChunkSize($this->updateTarget), $selectionList->markStale(); ); $selectionList->addEntityList(QueuePriorityEnum::HIGH, $staleWorkEntityIds); $selectionList->setChunkSize(ChunkSize::getStaleChunkSize($this->updateTarget)); return $selectionList; } } $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $selectionList->setChunkSize($mainChunkSize); $priorityEntityIdsList = $this->extractIdsFromSet( $priorityEntityIdsList = $this->extractIds(QueuePriorityEnum::HIGH, $mainChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, true), $selectionList->addEntityList(QueuePriorityEnum::HIGH, $priorityEntityIdsList); $mainChunkSize, ); $normalEntityIdsList = []; $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); if ($normalEntityChunkSize > 0) { if ($normalEntityChunkSize > 0) { $normalEntityIdsList = $this->extractIdsFromSet( $normalEntityIdsList = $this->extractIds(QueuePriorityEnum::NORMAL, $normalEntityChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, false), $selectionList->addEntityList(QueuePriorityEnum::NORMAL, $normalEntityIdsList); $normalEntityChunkSize ); } } return new SelectionList( return $selectionList; priorityEntityIdList: $priorityEntityIdsList, normalEntityIdList: $normalEntityIdsList, chunkSize: $mainChunkSize ); } } private function getStaleChunk(): array private function getStaleChunk(): array return []; return []; } } private function extractIds(QueuePriorityEnum $priority, int $chunkSize): array { return $this->extractIdsFromSet( AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, $priority), $chunkSize ); } } } app/Component/ES/AsyncUpdateElasticSearch.php +17-10Lines changed: 17 additions & 10 deletions Original file line numberOriginal file lineDiff line numberDiff line change * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * and other activity related data * and other activity related data */ */ public static function markEntityForUpdate(string $entityType, int $entityId, bool $withPriority = false): void public static function markEntityForUpdate( { string $entityType, $targetList = self::selectTargetList($entityType, $withPriority); int $entityId, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { $targetList = self::selectTargetList($entityType, $priority); Redis::sadd($targetList, $entityId); Redis::sadd($targetList, $entityId); Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ 'entityType' => $entityType, 'entityType' => $entityType, 'entityId' => $entityId, 'entityId' => $entityId, 'collectionKey' => $targetList, 'collectionKey' => $targetList, 'withPriority' => $withPriority, 'priority' => $priority->value, ]); ]); } } public static function bulkMarkEntitiesForUpdate( public static function bulkMarkEntitiesForUpdate( string $entityType, string $entityType, array $entityIds, array $entityIds, bool $withPriority = false QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { ): void { if (empty($entityIds)) { if (empty($entityIds)) { return; return; } } $targetList = self::selectTargetList($entityType, $withPriority); $targetList = self::selectTargetList($entityType, $priority); Redis::saddarray($targetList, $entityIds); Redis::saddarray($targetList, $entityIds); } } * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Takes priority into consideration. * Takes priority into consideration. */ */ public static function getEntitiesSourceList(string $updateTarget, $priority = false): string public static function getEntitiesSourceList( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { return self::selectTargetList($updateTarget, $priority); return self::selectTargetList($updateTarget, $priority); } } /** /** * Externally called helper methods * Externally called helper methods * - count and flush * - count and flush */ */ public static function getEntitiesListCount(string $updateTarget, $priority = false): int public static function getEntitiesListCount( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): int { $targetList = self::selectTargetList($updateTarget, $priority); $targetList = self::selectTargetList($updateTarget, $priority); return Redis::scard($targetList); return Redis::scard($targetList); app/Component/ES/QueuePriorityEnum.php +40Lines changed: 40 additions & 0 deletions Original file line numberOriginal file lineDiff line numberDiff line change <?php declare(strict_types=1); namespace Jiminny\\Component\\ES; use Jiminny\\Exceptions\\InvalidArgumentException; enum QueuePriorityEnum: string { case HIGH = 'high'; case NORMAL = 'normal'; case LOW = 'low'; public static function tryFromString(string $value): self { if (! self::isValid($value)) { throw new InvalidArgumentException( sprintf('Invalid queue priority \"%s\" selected', $value) ); } return self::tryFrom($value); } public static function isValid(string $value): bool { return self::tryFrom($value) !== null; } public function isLow(): bool { return $this === self::LOW; } public function isHigh(): bool { return $this === self::HIGH; } } app/Component/ES/UpdateProcessManager.php +12-9Lines changed: 12 additions & 9 deletions Original file line numberOriginal file lineDiff line numberDiff line change if ($selectionList->isEmpty()) { if ($selectionList->isEmpty()) { return false; return false; } } /** /** * A stale chunk will always be smaller than a regular chunk. * A stale chunk will always be smaller than a regular chunk. * That doesn't mean there aren't any other scheduled entities for processing * That doesn't mean there aren't any other scheduled entities for processing private function rescheduleThrottledEntities(SelectionList $selectionList): void private function rescheduleThrottledEntities(SelectionList $selectionList): void { { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $groups = $selectionList->getEntityListGroups(); $this->updateTarget, foreach ($groups as $eachGroup) { $selectionList->getNormalPriorityEntityId() $groupEntityIds = $selectionList->getEntityListItemsByGroup($eachGroup); ); if (! empty($groupEntityIds)) { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $this->updateTarget, entityType: $this->updateTarget, $selectionList->getHighPriorityEntityIds(), entityIds: $groupEntityIds, true priority: QueuePriorityEnum::tryFromString($eachGroup) ); ); } } } } } } app/Console/Commands/Elasticsearch/AsyncUpdateEsEntities.php +9-3Lines changed: 9 additions & 3 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Illuminate\\Support\\Str; use Illuminate\\Support\\Str; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Component\\ES\\UpdateProcessManager; use Jiminny\\Component\\ES\\UpdateProcessManager; use Jiminny\\Exceptions\\InvalidArgumentException; use Jiminny\\Exceptions\\InvalidArgumentException; use Jiminny\\Traits\\GracefullyStoppable; use Jiminny\\Traits\\GracefullyStoppable; Redis::set($gaugeLockName, true); Redis::set($gaugeLockName, true); Redis::expire($gaugeLockName, 60); Redis::expire($gaugeLockName, 60); $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::HIGH), ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update', $updateTarget), stat: sprintf('jiminny.%s-for-update', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::NORMAL), ); ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), stat: sprintf('jiminny.%s-for-update-low', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, true), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::LOW), ); ); } } app/Console/Commands/Elasticsearch/ResetAsyncElasticSearchCommand.php +5-1Lines changed: 5 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder; use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder; use Jiminny\\Component\\ES\\Processor\\Traits\\ValidateUpdateTargetTrait; use Jiminny\\Component\\ES\\Processor\\Traits\\ValidateUpdateTargetTrait; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Component\\ES\\Repositories\\EsResetRepositoryInterface; use Jiminny\\Component\\ES\\Repositories\\EsResetRepositoryInterface; use Jiminny\\Exceptions\\InvalidArgumentException; use Jiminny\\Exceptions\\InvalidArgumentException; use Jiminny\\Traits\\GracefullyStoppable; use Jiminny\\Traits\\GracefullyStoppable; private function getRemainingScheduledEntities(bool $printStatus = false): int private function getRemainingScheduledEntities(bool $printStatus = false): int { { $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget, true); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount( $this->updateTarget, QueuePriorityEnum::HIGH ); if ($printStatus) { if ($printStatus) { $this->line( $this->line(","depth":21,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"You said","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app/Component/ES/Listeners/UpdateMultipleTargetsListener.php","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"+2-1Lines changed: 2 additions & 1 deletion","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\\Component\\ES\\Listeners;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"namespace Jiminny\\Component\\ES\\Listeners;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\QueuePriorityEnum;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Contracts\\ES\\Events\\UpdateMultipleEntities;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Contracts\\ES\\Events\\UpdateMultipleEntities;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Psr\\Log\\LoggerInterface;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Psr\\Log\\LoggerInterface;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getUpdateTargetValue(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getUpdateTargetValue(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getEntities(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getEntities(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->isPriority()","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL,","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":");","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":");","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app/Component/ES/Listeners/UpdateSingleTargetListener.php","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"+9-1Lines changed: 9 additions & 1 deletion","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Actions\\TrackElasticSearchOperations;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Actions\\TrackElasticSearchOperations;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\QueuePriorityEnum;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Contracts\\ES\\Events\\UpdateSingleEntity;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Contracts\\ES\\Events\\UpdateSingleEntity;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Psr\\Log\\LoggerInterface;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Psr\\Log\\LoggerInterface;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"'entityId' => $event->getEntityId(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"'entityId' => $event->getEntityId(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"]);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"]);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/**","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* @important:","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* Synchronous event should eventually be deprecated.","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* Instant write operations are blocking and should be used sparingly.","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* It is much better in terms of performance to write 100 or 1000 documents at once,","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* and have one blocking reindex operation, instead of writing 10 documents synchronously.","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"*/","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"if ($event->isSyncEvent()) {","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"if ($event->isSyncEvent()) {","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$this->handleSyncEvent($event);","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$this->handleSyncEvent($event);","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AsyncUpdateElasticSearch::markEntityForUpdate(","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AsyncUpdateElasticSearch::markEntityForUpdate(","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getUpdateTargetValue(),","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getUpdateTargetValue(),","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getEntityId(),","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getEntityId(),","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->isPriority()","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL,","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":");","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":");","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app/Component/ES/Processor/Actions/UpsertDocumentsAction.php","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"+2-1Lines changed: 2 additions & 1 deletion","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Processor\\DTOs\\SimpleCollection;","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\DTOs\\SimpleCollection;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\ResponseEvaluator;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\ResponseEvaluator;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\QueuePriorityEnum;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Exceptions\\InvalidDataException;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Exceptions\\InvalidDataException;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Sentry\\Laravel\\Facade as Sentry;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Sentry\\Laravel\\Facade as Sentry;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AsyncUpdateElasticSearch::markEntityForUpdate(","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AsyncUpdateElasticSearch::markEntityForUpdate(","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"entityType: $this->updateTarget,","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"entityType: $this->updateTarget,","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"entityId: (int) $document->getId(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"entityId: (int) $document->getId(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"withPriority: true","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"priority: QueuePriorityEnum::HIGH,","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":");","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":");","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app/Component/ES/Processor/DTOs/SelectionList.php","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"+54-17Lines changed: 54 additions & 17 deletions","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Original file line numberOriginal file lineDiff line numberDiff line change","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"namespace Jiminny\\Component\\ES\\Processor\\DTOs;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"namespace Jiminny\\Component\\ES\\Processor\\DTOs;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\QueuePriorityEnum;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/**","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/**","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* A very basic and simple collection of entity IDs.","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* A very basic and simple collection of entity IDs.","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"*/","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"*/","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"class SelectionList","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"class SelectionList","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function __construct(","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private const int DEFAULT_CHUNK = 200;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private readonly array $priorityEntityIdList = [],","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private readonly array $normalEntityIdList = [],","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private int $chunkSize = self::DEFAULT_CHUNK;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private readonly bool $isStaleChunkSelected = false,","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private bool $isStaleChunkSelected = false;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private readonly int $chunkSize = 200,","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private array $selectedEntityIds = [];","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":") {","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"// Do nothing","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function setChunkSize(int $chunkSize): void","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$this->chunkSize = $chunkSize;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function getAllIds(): array","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function markStale(): void","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"return array_merge($this->priorityEntityIdList, $this->normalEntityIdList);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$this->isStaleChunkSelected = true;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"}]...
|
5568476771981713106
|
-1126437240719860594
|
click
|
accessibility
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
Close tab
New Tab
Customize sidebar
Close Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
AI Chat settings
Close
WORK, Google Account: [EMAIL]
Main menu
New chat
Gemini
New Chat
Open menu for conversation actions.
Conversation with Gemini
Conversation with Gemini
Show the uploaded image in a lightbox
Copy prompt
You said Make a PR of changes Find potential issues and bottlenecks
You said
Make a PR of changes Find potential issues and bottlenecks
Listen
Show thinking
Gemini said
Gemini said
I can see you've uploaded a screenshot of a code diff, likely from a version control system given the red and green highlights. I would love to help you review the changes, spot bottlenecks, and help you draft a Pull Request.
However,
the image resolution is far too low for me to read.
It appears to be a completely zoomed-out view where the code has been reduced to tiny, illegible pixels. Because of this, I cannot extract any text or logic to analyze.
How You Can Share the Code
How You Can Share the Code
To help me review your code effectively, please try one of the following:
Paste the text directly:
Copy the specific code blocks (both the old and new versions if possible) and paste them directly into our chat.
Upload the files:
If the changes are extensive, you can upload the raw text or code files.
Take high-resolution screenshots:
If you must use images, take closer, readable screenshots of the specific functions or methods you want me to review.
Once you provide the readable code, I can dive right in to identify potential bugs, assess performance bottlenecks, and help you summarize the changes for your PR!
Good response
Bad response
Share & export
Copy
Show more options
Copy prompt
Edit
You said app/Component/ES/Listeners/UpdateMultipleTargetsListener.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\Component\ES\Listeners; namespace Jiminny\Component\ES\Listeners; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Contracts\ES\Events\UpdateMultipleEntities; use Jiminny\Contracts\ES\Events\UpdateMultipleEntities; use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface; AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntities(), $event->getEntities(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } } } app/Component/ES/Listeners/UpdateSingleTargetListener.php +9-1Lines changed: 9 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Actions\TrackElasticSearchOperations; use Jiminny\Component\ES\Actions\TrackElasticSearchOperations; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Contracts\ES\Events\UpdateSingleEntity; use Jiminny\Contracts\ES\Events\UpdateSingleEntity; use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface; 'entityId' => $event->getEntityId(), 'entityId' => $event->getEntityId(), ]); ]); /** * @important: * Synchronous event should eventually be deprecated. * Instant write operations are blocking and should be used sparingly. * It is much better in terms of performance to write 100 or 1000 documents at once, * and have one blocking reindex operation, instead of writing 10 documents synchronously. */ if ($event->isSyncEvent()) { if ($event->isSyncEvent()) { $this->handleSyncEvent($event); $this->handleSyncEvent($event); AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntityId(), $event->getEntityId(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } app/Component/ES/Processor/Actions/UpsertDocumentsAction.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SimpleCollection; use Jiminny\Component\ES\Processor\DTOs\SimpleCollection; use Jiminny\Component\ES\Processor\ResponseEvaluator; use Jiminny\Component\ES\Processor\ResponseEvaluator; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Exceptions\InvalidDataException; use Jiminny\Exceptions\InvalidDataException; use Sentry\Laravel\Facade as Sentry; use Sentry\Laravel\Facade as Sentry; AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( entityType: $this->updateTarget, entityType: $this->updateTarget, entityId: (int) $document->getId(), entityId: (int) $document->getId(), withPriority: true priority: QueuePriorityEnum::HIGH, ); ); } } app/Component/ES/Processor/DTOs/SelectionList.php +54-17Lines changed: 54 additions & 17 deletions Original file line numberOriginal file lineDiff line numberDiff line change namespace Jiminny\Component\ES\Processor\DTOs; namespace Jiminny\Component\ES\Processor\DTOs; use Jiminny\Component\ES\QueuePriorityEnum; /** /** * A very basic and simple collection of entity IDs. * A very basic and simple collection of entity IDs. */ */ class SelectionList class SelectionList { { public function __construct( private const int DEFAULT_CHUNK = 200; private readonly array $priorityEntityIdList = [], private readonly array $normalEntityIdList = [], private int $chunkSize = self::DEFAULT_CHUNK; private readonly bool $isStaleChunkSelected = false, private bool $isStaleChunkSelected = false; private readonly int $chunkSize = 200, private array $selectedEntityIds = []; ) { // Do nothing public function setChunkSize(int $chunkSize): void { $this->chunkSize = $chunkSize; } } public function getAllIds(): array public function markStale(): void { { return array_merge($this->priorityEntityIdList, $this->normalEntityIdList); $this->isStaleChunkSelected = true; } } public function count(): int public function addEntityList(string|QueuePriorityEnum $priority, array $entityIds): void { { return count($this->priorityEntityIdList) + count($this->normalEntityIdList); $priorityKey = $this->normalisePriority($priority); if (! array_key_exists($priorityKey, $this->selectedEntityIds)) { $this->selectedEntityIds[$priorityKey] = []; } $this->selectedEntityIds[$priorityKey] = array_merge($this->selectedEntityIds[$priorityKey], $entityIds); } } public function isEmpty(): bool /** * @return string[] */ public function getEntityListGroups(): array { { return empty($this->priorityEntityIdList) && empty($this->normalEntityIdList); return array_keys($this->selectedEntityIds); } } public function getHighPriorityEntityIds(): array public function getEntityListItemsByGroup(string|QueuePriorityEnum $priority): array { { return $this->priorityEntityIdList; $priorityKey = $this->normalisePriority($priority); return $this->selectedEntityIds[$priorityKey] ?? []; } } public function getNormalPriorityEntityId(): array public function getAllIds(): array { { return $this->normalEntityIdList; $allIds = []; foreach ($this->selectedEntityIds as $entityIds) { $allIds = array_merge($allIds, $entityIds); } return $allIds; } public function count(): int { return array_sum( array_map('count', $this->selectedEntityIds) ); } public function isEmpty(): bool { return $this->count() === 0; } } public function isStaleChunkSelected(): bool public function isStaleChunkSelected(): bool { { return $this->count() >= $this->chunkSize; return $this->count() >= $this->chunkSize; } } private function normalisePriority(string|QueuePriorityEnum $priority): string { return $priority instanceof QueuePriorityEnum ? $priority->value : $priority; } } } app/Component/ES/Processor/Traits/SelectEntityListTrait.php +27-4Lines changed: 27 additions & 4 deletions Original file line numberOriginal file lineDiff line numberDiff line change use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; /** /** * Build the correct source list name for the type of entity and priority * Build the correct source list name for the type of entity and priority */ */ trait SelectEntityListTrait trait SelectEntityListTrait { { /** * Highest priority queue for data requiring near-instant availability. * Very few entities should be added here, only when absolutely necessary. */ private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; /** * Normal priority queue for normal application operations. * Almost all update events should pass through this queue */ private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; protected static function selectTargetList(string $entityType, bool $withPriority = false): string /** { * Nonblocking low priority queue. This queue will be consumed only when there is nothing * with higher priority. * * This queue will be used for operations such as es:reset-async */ private const string ENTITIES_LOW_PRIORITIES_LIST = '%s-for-update-low'; protected static function selectTargetList( string $entityType, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { if (! in_array($entityType, UpdateTarget::allowedTargets())) { if (! in_array($entityType, UpdateTarget::allowedTargets())) { throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); } } if ($withPriority) { if ($priority->isHigh()) { Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); } } if ($priority->isLow()) { return sprintf(self::ENTITIES_LOW_PRIORITIES_LIST, $entityType); } return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); } } } } app/Component/ES/Processor/TargetEntitiesSelector.php +26-21Lines changed: 26 additions & 21 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SelectionList; use Jiminny\Component\ES\Processor\DTOs\SelectionList; use Jiminny\Component\ES\Processor\Traits\ExtractIdsTrait; use Jiminny\Component\ES\Processor\Traits\ExtractIdsTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\QueuePriorityEnum; /** /** * This class supplies a list of entities pending an update. * This class supplies a list of entities pending an update. public function select(): SelectionList public function select(): SelectionList { { $staleWorkEntityIds = $this->getStaleChunk(); $selectionList = new SelectionList(); $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $staleWorkEntityIds = $this->getStaleChunk(); if (count($staleWorkEntityIds) > 0) { if (count($staleWorkEntityIds) > 0) { return new SelectionList( /** priorityEntityIdList: $staleWorkEntityIds, * Stale chunks are treated as high priority isStaleChunkSelected: true, */ chunkSize: ChunkSize::getStaleChunkSize($this->updateTarget), $selectionList->markStale(); ); $selectionList->addEntityList(QueuePriorityEnum::HIGH, $staleWorkEntityIds); $selectionList->setChunkSize(ChunkSize::getStaleChunkSize($this->updateTarget)); return $selectionList; } } $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $selectionList->setChunkSize($mainChunkSize); $priorityEntityIdsList = $this->extractIdsFromSet( $priorityEntityIdsList = $this->extractIds(QueuePriorityEnum::HIGH, $mainChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, true), $selectionList->addEntityList(QueuePriorityEnum::HIGH, $priorityEntityIdsList); $mainChunkSize, ); $normalEntityIdsList = []; $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); if ($normalEntityChunkSize > 0) { if ($normalEntityChunkSize > 0) { $normalEntityIdsList = $this->extractIdsFromSet( $normalEntityIdsList = $this->extractIds(QueuePriorityEnum::NORMAL, $normalEntityChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, false), $selectionList->addEntityList(QueuePriorityEnum::NORMAL, $normalEntityIdsList); $normalEntityChunkSize ); } } return new SelectionList( return $selectionList; priorityEntityIdList: $priorityEntityIdsList, normalEntityIdList: $normalEntityIdsList, chunkSize: $mainChunkSize ); } } private function getStaleChunk(): array private function getStaleChunk(): array return []; return []; } } private function extractIds(QueuePriorityEnum $priority, int $chunkSize): array { return $this->extractIdsFromSet( AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, $priority), $chunkSize ); } } } app/Component/ES/AsyncUpdateElasticSearch.php +17-10Lines changed: 17 additions & 10 deletions Original file line numberOriginal file lineDiff line numberDiff line change * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * and other activity related data * and other activity related data */ */ public static function markEntityForUpdate(string $entityType, int $entityId, bool $withPriority = false): void public static function markEntityForUpdate( { string $entityType, $targetList = self::selectTargetList($entityType, $withPriority); int $entityId, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { $targetList = self::selectTargetList($entityType, $priority); Redis::sadd($targetList, $entityId); Redis::sadd($targetList, $entityId); Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ 'entityType' => $entityType, 'entityType' => $entityType, 'entityId' => $entityId, 'entityId' => $entityId, 'collectionKey' => $targetList, 'collectionKey' => $targetList, 'withPriority' => $withPriority, 'priority' => $priority->value, ]); ]); } } public static function bulkMarkEntitiesForUpdate( public static function bulkMarkEntitiesForUpdate( string $entityType, string $entityType, array $entityIds, array $entityIds, bool $withPriority = false QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { ): void { if (empty($entityIds)) { if (empty($entityIds)) { return; return; } } $targetList = self::selectTargetList($entityType, $withPriority); $targetList = self::selectTargetList($entityType, $priority); Redis::saddarray($targetList, $entityIds); Redis::saddarray($targetList, $entityIds); } } * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Takes priority into consideration. * Takes priority into consideration. */ */ public static function getEntitiesSourceList(string $updateTarget, $priority = false): string public static function getEntitiesSourceList( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { return self::selectTargetList($updateTarget, $priority); return self::selectTargetList($updateTarget, $priority); } } /** /** * Externally called helper methods * Externally called helper methods * - count and flush * - count and flush */ */ public static function getEntitiesListCount(string $updateTarget, $priority = false): int public static function getEntitiesListCount( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): int { $targetList = self::selectTargetList($updateTarget, $priority); $targetList = self::selectTargetList($updateTarget, $priority); return Redis::scard($targetList); return Redis::scard($targetList); app/Component/ES/QueuePriorityEnum.php +40Lines changed: 40 additions & 0 deletions Original file line numberOriginal file lineDiff line numberDiff line change <?php declare(strict_types=1); namespace Jiminny\Component\ES; use Jiminny\Exceptions\InvalidArgumentException; enum QueuePriorityEnum: string { case HIGH = 'high'; case NORMAL = 'normal'; case LOW = 'low'; public static function tryFromString(string $value): self { if (! self::isValid($value)) { throw new InvalidArgumentException( sprintf('Invalid queue priority "%s" selected', $value) ); } return self::tryFrom($value); } public static function isValid(string $value): bool { return self::tryFrom($value) !== null; } public function isLow(): bool { return $this === self::LOW; } public function isHigh(): bool { return $this === self::HIGH; } } app/Component/ES/UpdateProcessManager.php +12-9Lines changed: 12 additions & 9 deletions Original file line numberOriginal file lineDiff line numberDiff line change if ($selectionList->isEmpty()) { if ($selectionList->isEmpty()) { return false; return false; } } /** /** * A stale chunk will always be smaller than a regular chunk. * A stale chunk will always be smaller than a regular chunk. * That doesn't mean there aren't any other scheduled entities for processing * That doesn't mean there aren't any other scheduled entities for processing private function rescheduleThrottledEntities(SelectionList $selectionList): void private function rescheduleThrottledEntities(SelectionList $selectionList): void { { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $groups = $selectionList->getEntityListGroups(); $this->updateTarget, foreach ($groups as $eachGroup) { $selectionList->getNormalPriorityEntityId() $groupEntityIds = $selectionList->getEntityListItemsByGroup($eachGroup); ); if (! empty($groupEntityIds)) { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $this->updateTarget, entityType: $this->updateTarget, $selectionList->getHighPriorityEntityIds(), entityIds: $groupEntityIds, true priority: QueuePriorityEnum::tryFromString($eachGroup) ); ); } } } } } } app/Console/Commands/Elasticsearch/AsyncUpdateEsEntities.php +9-3Lines changed: 9 additions & 3 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Illuminate\Support\Str; use Illuminate\Support\Str; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Component\ES\UpdateProcessManager; use Jiminny\Component\ES\UpdateProcessManager; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Traits\GracefullyStoppable; use Jiminny\Traits\GracefullyStoppable; Redis::set($gaugeLockName, true); Redis::set($gaugeLockName, true); Redis::expire($gaugeLockName, 60); Redis::expire($gaugeLockName, 60); $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::HIGH), ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update', $updateTarget), stat: sprintf('jiminny.%s-for-update', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::NORMAL), ); ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), stat: sprintf('jiminny.%s-for-update-low', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, true), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::LOW), ); ); } } app/Console/Commands/Elasticsearch/ResetAsyncElasticSearchCommand.php +5-1Lines changed: 5 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\Traits\ValidateUpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\ValidateUpdateTargetTrait; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Component\ES\Repositories\EsResetRepositoryInterface; use Jiminny\Component\ES\Repositories\EsResetRepositoryInterface; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Traits\GracefullyStoppable; use Jiminny\Traits\GracefullyStoppable; private function getRemainingScheduledEntities(bool $printStatus = false): int private function getRemainingScheduledEntities(bool $printStatus = false): int { { $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget, true); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount( $this->updateTarget, QueuePriorityEnum::HIGH ); if ($printStatus) { if ($printStatus) { $this->line( $this->line(
You said
app/Component/ES/Listeners/UpdateMultipleTargetsListener.php
+2-1Lines changed: 2 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\Component\ES\Listeners;
namespace Jiminny\Component\ES\Listeners;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\QueuePriorityEnum;
use Jiminny\Contracts\ES\Events\UpdateMultipleEntities;
use Jiminny\Contracts\ES\Events\UpdateMultipleEntities;
use Psr\Log\LoggerInterface;
use Psr\Log\LoggerInterface;
AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(
AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(
$event->getUpdateTargetValue(),
$event->getUpdateTargetValue(),
$event->getEntities(),
$event->getEntities(),
$event->isPriority()
$event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL,
);
);
}
}
}
}
app/Component/ES/Listeners/UpdateSingleTargetListener.php
+9-1Lines changed: 9 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Actions\TrackElasticSearchOperations;
use Jiminny\Component\ES\Actions\TrackElasticSearchOperations;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\Processor\EntityQueryBuilder;
use Jiminny\Component\ES\Processor\EntityQueryBuilder;
use Jiminny\Component\ES\QueuePriorityEnum;
use Jiminny\Contracts\ES\Events\UpdateSingleEntity;
use Jiminny\Contracts\ES\Events\UpdateSingleEntity;
use Psr\Log\LoggerInterface;
use Psr\Log\LoggerInterface;
'entityId' => $event->getEntityId(),
'entityId' => $event->getEntityId(),
]);
]);
/**
* @important:
* Synchronous event should eventually be deprecated.
* Instant write operations are blocking and should be used sparingly.
* It is much better in terms of performance to write 100 or 1000 documents at once,
* and have one blocking reindex operation, instead of writing 10 documents synchronously.
*/
if ($event->isSyncEvent()) {
if ($event->isSyncEvent()) {
$this->handleSyncEvent($event);
$this->handleSyncEvent($event);
AsyncUpdateElasticSearch::markEntityForUpdate(
AsyncUpdateElasticSearch::markEntityForUpdate(
$event->getUpdateTargetValue(),
$event->getUpdateTargetValue(),
$event->getEntityId(),
$event->getEntityId(),
$event->isPriority()
$event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL,
);
);
}
}
app/Component/ES/Processor/Actions/UpsertDocumentsAction.php
+2-1Lines changed: 2 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SimpleCollection;
use Jiminny\Component\ES\Processor\DTOs\SimpleCollection;
use Jiminny\Component\ES\Processor\ResponseEvaluator;
use Jiminny\Component\ES\Processor\ResponseEvaluator;
use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait;
use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait;
use Jiminny\Component\ES\QueuePriorityEnum;
use Jiminny\Exceptions\InvalidDataException;
use Jiminny\Exceptions\InvalidDataException;
use Sentry\Laravel\Facade as Sentry;
use Sentry\Laravel\Facade as Sentry;
AsyncUpdateElasticSearch::markEntityForUpdate(
AsyncUpdateElasticSearch::markEntityForUpdate(
entityType: $this->updateTarget,
entityType: $this->updateTarget,
entityId: (int) $document->getId(),
entityId: (int) $document->getId(),
withPriority: true
priority: QueuePriorityEnum::HIGH,
);
);
}
}
app/Component/ES/Processor/DTOs/SelectionList.php
+54-17Lines changed: 54 additions & 17 deletions
Original file line numberOriginal file lineDiff line numberDiff line change
namespace Jiminny\Component\ES\Processor\DTOs;
namespace Jiminny\Component\ES\Processor\DTOs;
use Jiminny\Component\ES\QueuePriorityEnum;
/**
/**
* A very basic and simple collection of entity IDs.
* A very basic and simple collection of entity IDs.
*/
*/
class SelectionList
class SelectionList
{
{
public function __construct(
private const int DEFAULT_CHUNK = 200;
private readonly array $priorityEntityIdList = [],
private readonly array $normalEntityIdList = [],
private int $chunkSize = self::DEFAULT_CHUNK;
private readonly bool $isStaleChunkSelected = false,
private bool $isStaleChunkSelected = false;
private readonly int $chunkSize = 200,
private array $selectedEntityIds = [];
) {
// Do nothing
public function setChunkSize(int $chunkSize): void
{
$this->chunkSize = $chunkSize;
}
}
public function getAllIds(): array
public function markStale(): void
{
{
return array_merge($this->priorityEntityIdList, $this->normalEntityIdList);
$this->isStaleChunkSelected = true;
}
}...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
55706
|
1934
|
4
|
2026-05-19T06:43:49.450719+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779173029450_m1.jpg...
|
Firefox
|
JY-20808 low priority indexing queue by Vasil-Jimi JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app — Work...
|
1
|
github.com/jiminny/app/pull/12082/changes#diff-616 github.com/jiminny/app/pull/12082/changes#diff-61654edeebd72388bddd97cafcac889a2d106f54bb484a719d4067878bb9b011...
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
Close tab
New Tab
Customize sidebar
Close Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
AI Chat settings
Close
WORK, Google Account: [EMAIL]
Main menu
New chat
Gemini
New Chat
Open menu for conversation actions.
Conversation with Gemini
Conversation with Gemini
Show the uploaded image in a lightbox
Copy prompt
You said Make a PR of changes Find potential issues and bottlenecks
You said
Make a PR of changes Find potential issues and bottlenecks
Listen
Show thinking
Gemini said
Gemini said
I can see you've uploaded a screenshot of a code diff, likely from a version control system given the red and green highlights. I would love to help you review the changes, spot bottlenecks, and help you draft a Pull Request.
However,
the image resolution is far too low for me to read.
It appears to be a completely zoomed-out view where the code has been reduced to tiny, illegible pixels. Because of this, I cannot extract any text or logic to analyze.
How You Can Share the Code
How You Can Share the Code
To help me review your code effectively, please try one of the following:
Paste the text directly:
Copy the specific code blocks (both the old and new versions if possible) and paste them directly into our chat.
Upload the files:
If the changes are extensive, you can upload the raw text or code files.
Take high-resolution screenshots:
If you must use images, take closer, readable screenshots of the specific functions or methods you want me to review.
Once you provide the readable code, I can dive right in to identify potential bugs, assess performance bottlenecks, and help you summarize the changes for your PR!
Good response
Bad response
Share & export
Copy
Show more options
Copy prompt
Edit
You said app/Component/ES/Listeners/UpdateMultipleTargetsListener.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\Component\ES\Listeners; namespace Jiminny\Component\ES\Listeners; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Contracts\ES\Events\UpdateMultipleEntities; use Jiminny\Contracts\ES\Events\UpdateMultipleEntities; use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface; AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntities(), $event->getEntities(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } } } app/Component/ES/Listeners/UpdateSingleTargetListener.php +9-1Lines changed: 9 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Actions\TrackElasticSearchOperations; use Jiminny\Component\ES\Actions\TrackElasticSearchOperations; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Contracts\ES\Events\UpdateSingleEntity; use Jiminny\Contracts\ES\Events\UpdateSingleEntity; use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface; 'entityId' => $event->getEntityId(), 'entityId' => $event->getEntityId(), ]); ]); /** * @important: * Synchronous event should eventually be deprecated. * Instant write operations are blocking and should be used sparingly. * It is much better in terms of performance to write 100 or 1000 documents at once, * and have one blocking reindex operation, instead of writing 10 documents synchronously. */ if ($event->isSyncEvent()) { if ($event->isSyncEvent()) { $this->handleSyncEvent($event); $this->handleSyncEvent($event); AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntityId(), $event->getEntityId(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } app/Component/ES/Processor/Actions/UpsertDocumentsAction.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SimpleCollection; use Jiminny\Component\ES\Processor\DTOs\SimpleCollection; use Jiminny\Component\ES\Processor\ResponseEvaluator; use Jiminny\Component\ES\Processor\ResponseEvaluator; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Exceptions\InvalidDataException; use Jiminny\Exceptions\InvalidDataException; use Sentry\Laravel\Facade as Sentry; use Sentry\Laravel\Facade as Sentry; AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( entityType: $this->updateTarget, entityType: $this->updateTarget, entityId: (int) $document->getId(), entityId: (int) $document->getId(), withPriority: true priority: QueuePriorityEnum::HIGH, ); ); } } app/Component/ES/Processor/DTOs/SelectionList.php +54-17Lines changed: 54 additions & 17 deletions Original file line numberOriginal file lineDiff line numberDiff line change namespace Jiminny\Component\ES\Processor\DTOs; namespace Jiminny\Component\ES\Processor\DTOs; use Jiminny\Component\ES\QueuePriorityEnum; /** /** * A very basic and simple collection of entity IDs. * A very basic and simple collection of entity IDs. */ */ class SelectionList class SelectionList { { public function __construct( private const int DEFAULT_CHUNK = 200; private readonly array $priorityEntityIdList = [], private readonly array $normalEntityIdList = [], private int $chunkSize = self::DEFAULT_CHUNK; private readonly bool $isStaleChunkSelected = false, private bool $isStaleChunkSelected = false; private readonly int $chunkSize = 200, private array $selectedEntityIds = []; ) { // Do nothing public function setChunkSize(int $chunkSize): void { $this->chunkSize = $chunkSize; } } public function getAllIds(): array public function markStale(): void { { return array_merge($this->priorityEntityIdList, $this->normalEntityIdList); $this->isStaleChunkSelected = true; } } public function count(): int public function addEntityList(string|QueuePriorityEnum $priority, array $entityIds): void { { return count($this->priorityEntityIdList) + count($this->normalEntityIdList); $priorityKey = $this->normalisePriority($priority); if (! array_key_exists($priorityKey, $this->selectedEntityIds)) { $this->selectedEntityIds[$priorityKey] = []; } $this->selectedEntityIds[$priorityKey] = array_merge($this->selectedEntityIds[$priorityKey], $entityIds); } } public function isEmpty(): bool /** * @return string[] */ public function getEntityListGroups(): array { { return empty($this->priorityEntityIdList) && empty($this->normalEntityIdList); return array_keys($this->selectedEntityIds); } } public function getHighPriorityEntityIds(): array public function getEntityListItemsByGroup(string|QueuePriorityEnum $priority): array { { return $this->priorityEntityIdList; $priorityKey = $this->normalisePriority($priority); return $this->selectedEntityIds[$priorityKey] ?? []; } } public function getNormalPriorityEntityId(): array public function getAllIds(): array { { return $this->normalEntityIdList; $allIds = []; foreach ($this->selectedEntityIds as $entityIds) { $allIds = array_merge($allIds, $entityIds); } return $allIds; } public function count(): int { return array_sum( array_map('count', $this->selectedEntityIds) ); } public function isEmpty(): bool { return $this->count() === 0; } } public function isStaleChunkSelected(): bool public function isStaleChunkSelected(): bool { { return $this->count() >= $this->chunkSize; return $this->count() >= $this->chunkSize; } } private function normalisePriority(string|QueuePriorityEnum $priority): string { return $priority instanceof QueuePriorityEnum ? $priority->value : $priority; } } } app/Component/ES/Processor/Traits/SelectEntityListTrait.php +27-4Lines changed: 27 additions & 4 deletions Original file line numberOriginal file lineDiff line numberDiff line change use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; /** /** * Build the correct source list name for the type of entity and priority * Build the correct source list name for the type of entity and priority */ */ trait SelectEntityListTrait trait SelectEntityListTrait { { /** * Highest priority queue for data requiring near-instant availability. * Very few entities should be added here, only when absolutely necessary. */ private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; /** * Normal priority queue for normal application operations. * Almost all update events should pass through this queue */ private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; protected static function selectTargetList(string $entityType, bool $withPriority = false): string /** { * Nonblocking low priority queue. This queue will be consumed only when there is nothing * with higher priority. * * This queue will be used for operations such as es:reset-async */ private const string ENTITIES_LOW_PRIORITIES_LIST = '%s-for-update-low'; protected static function selectTargetList( string $entityType, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { if (! in_array($entityType, UpdateTarget::allowedTargets())) { if (! in_array($entityType, UpdateTarget::allowedTargets())) { throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); } } if ($withPriority) { if ($priority->isHigh()) { Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); } } if ($priority->isLow()) { return sprintf(self::ENTITIES_LOW_PRIORITIES_LIST, $entityType); } return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); } } } } app/Component/ES/Processor/TargetEntitiesSelector.php +26-21Lines changed: 26 additions & 21 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SelectionList; use Jiminny\Component\ES\Processor\DTOs\SelectionList; use Jiminny\Component\ES\Processor\Traits\ExtractIdsTrait; use Jiminny\Component\ES\Processor\Traits\ExtractIdsTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\QueuePriorityEnum; /** /** * This class supplies a list of entities pending an update. * This class supplies a list of entities pending an update. public function select(): SelectionList public function select(): SelectionList { { $staleWorkEntityIds = $this->getStaleChunk(); $selectionList = new SelectionList(); $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $staleWorkEntityIds = $this->getStaleChunk(); if (count($staleWorkEntityIds) > 0) { if (count($staleWorkEntityIds) > 0) { return new SelectionList( /** priorityEntityIdList: $staleWorkEntityIds, * Stale chunks are treated as high priority isStaleChunkSelected: true, */ chunkSize: ChunkSize::getStaleChunkSize($this->updateTarget), $selectionList->markStale(); ); $selectionList->addEntityList(QueuePriorityEnum::HIGH, $staleWorkEntityIds); $selectionList->setChunkSize(ChunkSize::getStaleChunkSize($this->updateTarget)); return $selectionList; } } $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $selectionList->setChunkSize($mainChunkSize); $priorityEntityIdsList = $this->extractIdsFromSet( $priorityEntityIdsList = $this->extractIds(QueuePriorityEnum::HIGH, $mainChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, true), $selectionList->addEntityList(QueuePriorityEnum::HIGH, $priorityEntityIdsList); $mainChunkSize, ); $normalEntityIdsList = []; $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); if ($normalEntityChunkSize > 0) { if ($normalEntityChunkSize > 0) { $normalEntityIdsList = $this->extractIdsFromSet( $normalEntityIdsList = $this->extractIds(QueuePriorityEnum::NORMAL, $normalEntityChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, false), $selectionList->addEntityList(QueuePriorityEnum::NORMAL, $normalEntityIdsList); $normalEntityChunkSize ); } } return new SelectionList( return $selectionList; priorityEntityIdList: $priorityEntityIdsList, normalEntityIdList: $normalEntityIdsList, chunkSize: $mainChunkSize ); } } private function getStaleChunk(): array private function getStaleChunk(): array return []; return []; } } private function extractIds(QueuePriorityEnum $priority, int $chunkSize): array { return $this->extractIdsFromSet( AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, $priority), $chunkSize ); } } } app/Component/ES/AsyncUpdateElasticSearch.php +17-10Lines changed: 17 additions & 10 deletions Original file line numberOriginal file lineDiff line numberDiff line change * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * and other activity related data * and other activity related data */ */ public static function markEntityForUpdate(string $entityType, int $entityId, bool $withPriority = false): void public static function markEntityForUpdate( { string $entityType, $targetList = self::selectTargetList($entityType, $withPriority); int $entityId, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { $targetList = self::selectTargetList($entityType, $priority); Redis::sadd($targetList, $entityId); Redis::sadd($targetList, $entityId); Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ 'entityType' => $entityType, 'entityType' => $entityType, 'entityId' => $entityId, 'entityId' => $entityId, 'collectionKey' => $targetList, 'collectionKey' => $targetList, 'withPriority' => $withPriority, 'priority' => $priority->value, ]); ]); } } public static function bulkMarkEntitiesForUpdate( public static function bulkMarkEntitiesForUpdate( string $entityType, string $entityType, array $entityIds, array $entityIds, bool $withPriority = false QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { ): void { if (empty($entityIds)) { if (empty($entityIds)) { return; return; } } $targetList = self::selectTargetList($entityType, $withPriority); $targetList = self::selectTargetList($entityType, $priority); Redis::saddarray($targetList, $entityIds); Redis::saddarray($targetList, $entityIds); } } * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Takes priority into consideration. * Takes priority into consideration. */ */ public static function getEntitiesSourceList(string $updateTarget, $priority = false): string public static function getEntitiesSourceList( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { return self::selectTargetList($updateTarget, $priority); return self::selectTargetList($updateTarget, $priority); } } /** /** * Externally called helper methods * Externally called helper methods * - count and flush * - count and flush */ */ public static function getEntitiesListCount(string $updateTarget, $priority = false): int public static function getEntitiesListCount( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): int { $targetList = self::selectTargetList($updateTarget, $priority); $targetList = self::selectTargetList($updateTarget, $priority); return Redis::scard($targetList); return Redis::scard($targetList); app/Component/ES/QueuePriorityEnum.php +40Lines changed: 40 additions & 0 deletions Original file line numberOriginal file lineDiff line numberDiff line change <?php declare(strict_types=1); namespace Jiminny\Component\ES; use Jiminny\Exceptions\InvalidArgumentException; enum QueuePriorityEnum: string { case HIGH = 'high'; case NORMAL = 'normal'; case LOW = 'low'; public static function tryFromString(string $value): self { if (! self::isValid($value)) { throw new InvalidArgumentException( sprintf('Invalid queue priority "%s" selected', $value) ); } return self::tryFrom($value); } public static function isValid(string $value): bool { return self::tryFrom($value) !== null; } public function isLow(): bool { return $this === self::LOW; } public function isHigh(): bool { return $this === self::HIGH; } } app/Component/ES/UpdateProcessManager.php +12-9Lines changed: 12 additions & 9 deletions Original file line numberOriginal file lineDiff line numberDiff line change if ($selectionList->isEmpty()) { if ($selectionList->isEmpty()) { return false; return false; } } /** /** * A stale chunk will always be smaller than a regular chunk. * A stale chunk will always be smaller than a regular chunk. * That doesn't mean there aren't any other scheduled entities for processing * That doesn't mean there aren't any other scheduled entities for processing private function rescheduleThrottledEntities(SelectionList $selectionList): void private function rescheduleThrottledEntities(SelectionList $selectionList): void { { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $groups = $selectionList->getEntityListGroups(); $this->updateTarget, foreach ($groups as $eachGroup) { $selectionList->getNormalPriorityEntityId() $groupEntityIds = $selectionList->getEntityListItemsByGroup($eachGroup); ); if (! empty($groupEntityIds)) { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $this->updateTarget, entityType: $this->updateTarget, $selectionList->getHighPriorityEntityIds(), entityIds: $groupEntityIds, true priority: QueuePriorityEnum::tryFromString($eachGroup) ); ); } } } } } } app/Console/Commands/Elasticsearch/AsyncUpdateEsEntities.php +9-3Lines changed: 9 additions & 3 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Illuminate\Support\Str; use Illuminate\Support\Str; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Component\ES\UpdateProcessManager; use Jiminny\Component\ES\UpdateProcessManager; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Traits\GracefullyStoppable; use Jiminny\Traits\GracefullyStoppable; Redis::set($gaugeLockName, true); Redis::set($gaugeLockName, true); Redis::expire($gaugeLockName, 60); Redis::expire($gaugeLockName, 60); $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::HIGH), ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update', $updateTarget), stat: sprintf('jiminny.%s-for-update', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::NORMAL), ); ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), stat: sprintf('jiminny.%s-for-update-low', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, true), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::LOW), ); ); } } app/Console/Commands/Elasticsearch/ResetAsyncElasticSearchCommand.php +5-1Lines changed: 5 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\Traits\ValidateUpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\ValidateUpdateTargetTrait; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Component\ES\Repositories\EsResetRepositoryInterface; use Jiminny\Component\ES\Repositories\EsResetRepositoryInterface; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Traits\GracefullyStoppable; use Jiminny\Traits\GracefullyStoppable; private function getRemainingScheduledEntities(bool $printStatus = false): int private function getRemainingScheduledEntities(bool $printStatus = false): int { { $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget, true); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount( $this->updateTarget, QueuePriorityEnum::HIGH ); if ($printStatus) { if ($printStatus) { $this->line( $this->line(
You said
app/Component/ES/Listeners/UpdateMultipleTargetsListener.php
+2-1Lines changed: 2 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\Component\ES\Listeners;
namespace Jiminny\Component\ES\Listeners;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\QueuePriorityEnum;
use Jiminny\Contracts\ES\Events\UpdateMultipleEntities;
use Jiminny\Contracts\ES\Events\UpdateMultipleEntities;
use Psr\Log\LoggerInterface;
use Psr\Log\LoggerInterface;
AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(
AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(
$event->getUpdateTargetValue(),
$event->getUpdateTargetValue(),
$event->getEntities(),
$event->getEntities(),
$event->isPriority()
$event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL,
);
);
}
}
}
}
app/Component/ES/Listeners/UpdateSingleTargetListener.php
+9-1Lines changed: 9 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Actions\TrackElasticSearchOperations;
use Jiminny\Component\ES\Actions\TrackElasticSearchOperations;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\Processor\EntityQueryBuilder;
use Jiminny\Component\ES\Processor\EntityQueryBuilder;
use Jiminny\Component\ES\QueuePriorityEnum;
use Jiminny\Contracts\ES\Events\UpdateSingleEntity;
use Jiminny\Contracts\ES\Events\UpdateSingleEntity;
use Psr\Log\LoggerInterface;
use Psr\Log\LoggerInterface;
'entityId' => $event->getEntityId(),
'entityId' => $event->getEntityId(),
]);
]);
/**
* @important:
* Synchronous event should eventually be deprecated.
* Instant write operations are blocking and should be used sparingly.
* It is much better in terms of performance to write 100 or 1000 documents at once,
* and have one blocking reindex operation, instead of writing 10 documents synchronously.
*/
if ($event->isSyncEvent()) {
if ($event->isSyncEvent()) {
$this->handleSyncEvent($event);
$this->handleSyncEvent($event);
AsyncUpdateElasticSearch::markEntityForUpdate(
AsyncUpdateElasticSearch::markEntityForUpdate(
$event->getUpdateTargetValue(),
$event->getUpdateTargetValue(),
$event->getEntityId(),
$event->getEntityId(),
$event->isPriority()
$event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL,
);
);
}
}
app/Component/ES/Processor/Actions/UpsertDocumentsAction.php
+2-1Lines changed: 2 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SimpleCollection;
use Jiminny\Component\ES\Processor\DTOs\SimpleCollection;
use Jiminny\Component\ES\Processor\ResponseEvaluator;
use Jiminny\Component\ES\Processor\ResponseEvaluator;
use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait;
use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait;
use Jiminny\Component\ES\QueuePriorityEnum;
use Jiminny\Exceptions\InvalidDataException;
use Jiminny\Exceptions\InvalidDataException;
use Sentry\Laravel\Facade as Sentry;
use Sentry\Laravel\Facade as Sentry;
AsyncUpdateElasticSearch::markEntityForUpdate(
AsyncUpdateElasticSearch::markEntityForUpdate(
entityType: $this->updateTarget,
entityType: $this->updateTarget,
entityId: (int) $document->getId(),
entityId: (int) $document->getId(),
withPriority: true
priority: QueuePriorityEnum::HIGH,
);
);
}
}
app/Component/ES/Processor/DTOs/SelectionList.php
+54-17Lines changed: 54 additions & 17 deletions
Original file line numberOriginal file lineDiff line numberDiff line change
namespace Jiminny\Component\ES\Processor\DTOs;
namespace Jiminny\Component\ES\Processor\DTOs;
use Jiminny\Component\ES\QueuePriorityEnum;
/**
/**
* A very basic and simple collection of entity IDs.
* A very basic and simple collection of entity IDs.
*/
*/
class SelectionList
class SelectionList
{
{
public function __construct(
private const int DEFAULT_CHUNK = 200;
private readonly array $priorityEntityIdList = [],
private readonly array $normalEntityIdList = [],
private int $chunkSize = self::DEFAULT_CHUNK;
private readonly bool $isStaleChunkSelected = false,
private bool $isStaleChunkSelected = false;
private readonly int $chunkSize = 200,
private array $selectedEntityIds = [];
) {
// Do nothing
public function setChunkSize(int $chunkSize): void
{
$this->chunkSize = $chunkSize;
}
}
public function getAllIds(): array
public function markStale(): void
{
{
return array_merge($this->priorityEntityIdList, $this->normalEntityIdList);
$this->isStaleChunkSelected = true;
}
}
public function count(): int
public function addEntityList(string|QueuePriorityEnum $priority, array $entityIds): void
{
{
return count($this->priorityEntityIdList) + count($this->normalEntityIdList);
$priorityKey = $this->normalisePriority($priority);
if (! array_key_exists($priorityKey, $this->selectedEntityIds)) {
$this->selectedEntityIds[$priorityKey] = [];
}
$this->selectedEntityIds[$priorityKey] = array_merge($this->selectedEntityIds[$priorityKey], $entityIds);
}
}
public function isEmpty(): bool
/**
* @return string[]
*/
public function getEntityListGroups(): array
{
{
return empty($this->priorityEntityIdList) && empty($this->normalEntityIdList);
return array_keys($this->selectedEntityIds);
}
}
public function getHighPriorityEntityIds(): array
public function getEntityListItemsByGroup(string|QueuePriorityEnum $priority): array
{
{
return $this->priorityEntityIdList;
$priorityKey = $this->normalisePriority($priority);
return $this->selectedEntityIds[$priorityKey] ?? [];
}
}
public function getNormalPriorityEntityId(): array
public function getAllIds(): array
{
{
return $this->normalEntityIdList;
$allIds = [];
foreach ($this->selectedEntityIds as $entityIds) {
$allIds = array_merge($allIds, $entityIds);
}
return $allIds;
}
public function count(): int
{
return array_sum(
array_map('count', $this->selectedEntityIds)
);
}
public function isEmpty(): bool
{
return $this->count() === 0;
}
}
public function isStaleChunkSelected(): bool
public function isStaleChunkSelected(): bool
{
{
return $this->count() >= $this->chunkSize;
return $this->count() >= $this->chunkSize;
}
}
private function normalisePriority(string|QueuePriorityEnum $priority): string
{
return $priority instanceof QueuePriorityEnum ? $priority->value : $priority;
}
}
}
app/Component/ES/Processor/Traits/SelectEntityListTrait.php
+27-4Lines changed: 27 additions & 4 deletions
Original file line numberOriginal file lineDiff line numberDiff line change
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Log;...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New Tab","depth":4,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Close Google Gemini (⌃X)","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Tabs from other devices","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"AI Chat settings","depth":7,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Close","depth":7,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"WORK, Google Account: lukas.kovalik@jiminny.com","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Main menu","depth":12,"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New chat","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Gemini","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"New Chat","depth":12,"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Open menu for conversation actions.","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXHeading","text":"Conversation with Gemini","depth":15,"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Conversation with Gemini","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Show the uploaded image in a lightbox","depth":21,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy prompt","depth":21,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"You said Make a PR of changes Find potential issues and bottlenecks","depth":21,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"You said","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Make a PR of changes Find potential issues and bottlenecks","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Listen","depth":22,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Show thinking","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Gemini said","depth":20,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Gemini said","depth":21,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"I can see you've uploaded a screenshot of a code diff, likely from a version control system given the red and green highlights. I would love to help you review the changes, spot bottlenecks, and help you draft a Pull Request.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"However,","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"the image resolution is far too low for me to read.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"It appears to be a completely zoomed-out view where the code has been reduced to tiny, illegible pixels. Because of this, I cannot extract any text or logic to analyze.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"How You Can Share the Code","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"How You Can Share the Code","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"To help me review your code effectively, please try one of the following:","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Paste the text directly:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Copy the specific code blocks (both the old and new versions if possible) and paste them directly into our chat.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Upload the files:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"If the changes are extensive, you can upload the raw text or code files.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Take high-resolution screenshots:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"If you must use images, take closer, readable screenshots of the specific functions or methods you want me to review.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Once you provide the readable code, I can dive right in to identify potential bugs, assess performance bottlenecks, and help you summarize the changes for your PR!","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Good response","depth":22,"on_screen":false,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Bad response","depth":22,"on_screen":false,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Share & export","depth":21,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy","depth":22,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Show more options","depth":21,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy prompt","depth":21,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Edit","depth":21,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"You said app/Component/ES/Listeners/UpdateMultipleTargetsListener.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\\Component\\ES\\Listeners; namespace Jiminny\\Component\\ES\\Listeners; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Contracts\\ES\\Events\\UpdateMultipleEntities; use Jiminny\\Contracts\\ES\\Events\\UpdateMultipleEntities; use Psr\\Log\\LoggerInterface; use Psr\\Log\\LoggerInterface; AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntities(), $event->getEntities(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } } } app/Component/ES/Listeners/UpdateSingleTargetListener.php +9-1Lines changed: 9 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Actions\\TrackElasticSearchOperations; use Jiminny\\Component\\ES\\Actions\\TrackElasticSearchOperations; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder; use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Contracts\\ES\\Events\\UpdateSingleEntity; use Jiminny\\Contracts\\ES\\Events\\UpdateSingleEntity; use Psr\\Log\\LoggerInterface; use Psr\\Log\\LoggerInterface; 'entityId' => $event->getEntityId(), 'entityId' => $event->getEntityId(), ]); ]); /** * @important: * Synchronous event should eventually be deprecated. * Instant write operations are blocking and should be used sparingly. * It is much better in terms of performance to write 100 or 1000 documents at once, * and have one blocking reindex operation, instead of writing 10 documents synchronously. */ if ($event->isSyncEvent()) { if ($event->isSyncEvent()) { $this->handleSyncEvent($event); $this->handleSyncEvent($event); AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntityId(), $event->getEntityId(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } app/Component/ES/Processor/Actions/UpsertDocumentsAction.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Processor\\DTOs\\SimpleCollection; use Jiminny\\Component\\ES\\Processor\\DTOs\\SimpleCollection; use Jiminny\\Component\\ES\\Processor\\ResponseEvaluator; use Jiminny\\Component\\ES\\Processor\\ResponseEvaluator; use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait; use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Exceptions\\InvalidDataException; use Jiminny\\Exceptions\\InvalidDataException; use Sentry\\Laravel\\Facade as Sentry; use Sentry\\Laravel\\Facade as Sentry; AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( entityType: $this->updateTarget, entityType: $this->updateTarget, entityId: (int) $document->getId(), entityId: (int) $document->getId(), withPriority: true priority: QueuePriorityEnum::HIGH, ); ); } } app/Component/ES/Processor/DTOs/SelectionList.php +54-17Lines changed: 54 additions & 17 deletions Original file line numberOriginal file lineDiff line numberDiff line change namespace Jiminny\\Component\\ES\\Processor\\DTOs; namespace Jiminny\\Component\\ES\\Processor\\DTOs; use Jiminny\\Component\\ES\\QueuePriorityEnum; /** /** * A very basic and simple collection of entity IDs. * A very basic and simple collection of entity IDs. */ */ class SelectionList class SelectionList { { public function __construct( private const int DEFAULT_CHUNK = 200; private readonly array $priorityEntityIdList = [], private readonly array $normalEntityIdList = [], private int $chunkSize = self::DEFAULT_CHUNK; private readonly bool $isStaleChunkSelected = false, private bool $isStaleChunkSelected = false; private readonly int $chunkSize = 200, private array $selectedEntityIds = []; ) { // Do nothing public function setChunkSize(int $chunkSize): void { $this->chunkSize = $chunkSize; } } public function getAllIds(): array public function markStale(): void { { return array_merge($this->priorityEntityIdList, $this->normalEntityIdList); $this->isStaleChunkSelected = true; } } public function count(): int public function addEntityList(string|QueuePriorityEnum $priority, array $entityIds): void { { return count($this->priorityEntityIdList) + count($this->normalEntityIdList); $priorityKey = $this->normalisePriority($priority); if (! array_key_exists($priorityKey, $this->selectedEntityIds)) { $this->selectedEntityIds[$priorityKey] = []; } $this->selectedEntityIds[$priorityKey] = array_merge($this->selectedEntityIds[$priorityKey], $entityIds); } } public function isEmpty(): bool /** * @return string[] */ public function getEntityListGroups(): array { { return empty($this->priorityEntityIdList) && empty($this->normalEntityIdList); return array_keys($this->selectedEntityIds); } } public function getHighPriorityEntityIds(): array public function getEntityListItemsByGroup(string|QueuePriorityEnum $priority): array { { return $this->priorityEntityIdList; $priorityKey = $this->normalisePriority($priority); return $this->selectedEntityIds[$priorityKey] ?? []; } } public function getNormalPriorityEntityId(): array public function getAllIds(): array { { return $this->normalEntityIdList; $allIds = []; foreach ($this->selectedEntityIds as $entityIds) { $allIds = array_merge($allIds, $entityIds); } return $allIds; } public function count(): int { return array_sum( array_map('count', $this->selectedEntityIds) ); } public function isEmpty(): bool { return $this->count() === 0; } } public function isStaleChunkSelected(): bool public function isStaleChunkSelected(): bool { { return $this->count() >= $this->chunkSize; return $this->count() >= $this->chunkSize; } } private function normalisePriority(string|QueuePriorityEnum $priority): string { return $priority instanceof QueuePriorityEnum ? $priority->value : $priority; } } } app/Component/ES/Processor/Traits/SelectEntityListTrait.php +27-4Lines changed: 27 additions & 4 deletions Original file line numberOriginal file lineDiff line numberDiff line change use Illuminate\\Support\\Facades\\Log; use Illuminate\\Support\\Facades\\Log; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Exceptions\\InvalidArgumentException; use Jiminny\\Exceptions\\InvalidArgumentException; /** /** * Build the correct source list name for the type of entity and priority * Build the correct source list name for the type of entity and priority */ */ trait SelectEntityListTrait trait SelectEntityListTrait { { /** * Highest priority queue for data requiring near-instant availability. * Very few entities should be added here, only when absolutely necessary. */ private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; /** * Normal priority queue for normal application operations. * Almost all update events should pass through this queue */ private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; protected static function selectTargetList(string $entityType, bool $withPriority = false): string /** { * Nonblocking low priority queue. This queue will be consumed only when there is nothing * with higher priority. * * This queue will be used for operations such as es:reset-async */ private const string ENTITIES_LOW_PRIORITIES_LIST = '%s-for-update-low'; protected static function selectTargetList( string $entityType, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { if (! in_array($entityType, UpdateTarget::allowedTargets())) { if (! in_array($entityType, UpdateTarget::allowedTargets())) { throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); } } if ($withPriority) { if ($priority->isHigh()) { Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); } } if ($priority->isLow()) { return sprintf(self::ENTITIES_LOW_PRIORITIES_LIST, $entityType); } return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); } } } } app/Component/ES/Processor/TargetEntitiesSelector.php +26-21Lines changed: 26 additions & 21 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Processor\\DTOs\\SelectionList; use Jiminny\\Component\\ES\\Processor\\DTOs\\SelectionList; use Jiminny\\Component\\ES\\Processor\\Traits\\ExtractIdsTrait; use Jiminny\\Component\\ES\\Processor\\Traits\\ExtractIdsTrait; use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait; use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait; use Jiminny\\Component\\ES\\QueuePriorityEnum; /** /** * This class supplies a list of entities pending an update. * This class supplies a list of entities pending an update. public function select(): SelectionList public function select(): SelectionList { { $staleWorkEntityIds = $this->getStaleChunk(); $selectionList = new SelectionList(); $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $staleWorkEntityIds = $this->getStaleChunk(); if (count($staleWorkEntityIds) > 0) { if (count($staleWorkEntityIds) > 0) { return new SelectionList( /** priorityEntityIdList: $staleWorkEntityIds, * Stale chunks are treated as high priority isStaleChunkSelected: true, */ chunkSize: ChunkSize::getStaleChunkSize($this->updateTarget), $selectionList->markStale(); ); $selectionList->addEntityList(QueuePriorityEnum::HIGH, $staleWorkEntityIds); $selectionList->setChunkSize(ChunkSize::getStaleChunkSize($this->updateTarget)); return $selectionList; } } $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $selectionList->setChunkSize($mainChunkSize); $priorityEntityIdsList = $this->extractIdsFromSet( $priorityEntityIdsList = $this->extractIds(QueuePriorityEnum::HIGH, $mainChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, true), $selectionList->addEntityList(QueuePriorityEnum::HIGH, $priorityEntityIdsList); $mainChunkSize, ); $normalEntityIdsList = []; $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); if ($normalEntityChunkSize > 0) { if ($normalEntityChunkSize > 0) { $normalEntityIdsList = $this->extractIdsFromSet( $normalEntityIdsList = $this->extractIds(QueuePriorityEnum::NORMAL, $normalEntityChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, false), $selectionList->addEntityList(QueuePriorityEnum::NORMAL, $normalEntityIdsList); $normalEntityChunkSize ); } } return new SelectionList( return $selectionList; priorityEntityIdList: $priorityEntityIdsList, normalEntityIdList: $normalEntityIdsList, chunkSize: $mainChunkSize ); } } private function getStaleChunk(): array private function getStaleChunk(): array return []; return []; } } private function extractIds(QueuePriorityEnum $priority, int $chunkSize): array { return $this->extractIdsFromSet( AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, $priority), $chunkSize ); } } } app/Component/ES/AsyncUpdateElasticSearch.php +17-10Lines changed: 17 additions & 10 deletions Original file line numberOriginal file lineDiff line numberDiff line change * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * and other activity related data * and other activity related data */ */ public static function markEntityForUpdate(string $entityType, int $entityId, bool $withPriority = false): void public static function markEntityForUpdate( { string $entityType, $targetList = self::selectTargetList($entityType, $withPriority); int $entityId, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { $targetList = self::selectTargetList($entityType, $priority); Redis::sadd($targetList, $entityId); Redis::sadd($targetList, $entityId); Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ 'entityType' => $entityType, 'entityType' => $entityType, 'entityId' => $entityId, 'entityId' => $entityId, 'collectionKey' => $targetList, 'collectionKey' => $targetList, 'withPriority' => $withPriority, 'priority' => $priority->value, ]); ]); } } public static function bulkMarkEntitiesForUpdate( public static function bulkMarkEntitiesForUpdate( string $entityType, string $entityType, array $entityIds, array $entityIds, bool $withPriority = false QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { ): void { if (empty($entityIds)) { if (empty($entityIds)) { return; return; } } $targetList = self::selectTargetList($entityType, $withPriority); $targetList = self::selectTargetList($entityType, $priority); Redis::saddarray($targetList, $entityIds); Redis::saddarray($targetList, $entityIds); } } * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Takes priority into consideration. * Takes priority into consideration. */ */ public static function getEntitiesSourceList(string $updateTarget, $priority = false): string public static function getEntitiesSourceList( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { return self::selectTargetList($updateTarget, $priority); return self::selectTargetList($updateTarget, $priority); } } /** /** * Externally called helper methods * Externally called helper methods * - count and flush * - count and flush */ */ public static function getEntitiesListCount(string $updateTarget, $priority = false): int public static function getEntitiesListCount( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): int { $targetList = self::selectTargetList($updateTarget, $priority); $targetList = self::selectTargetList($updateTarget, $priority); return Redis::scard($targetList); return Redis::scard($targetList); app/Component/ES/QueuePriorityEnum.php +40Lines changed: 40 additions & 0 deletions Original file line numberOriginal file lineDiff line numberDiff line change <?php declare(strict_types=1); namespace Jiminny\\Component\\ES; use Jiminny\\Exceptions\\InvalidArgumentException; enum QueuePriorityEnum: string { case HIGH = 'high'; case NORMAL = 'normal'; case LOW = 'low'; public static function tryFromString(string $value): self { if (! self::isValid($value)) { throw new InvalidArgumentException( sprintf('Invalid queue priority \"%s\" selected', $value) ); } return self::tryFrom($value); } public static function isValid(string $value): bool { return self::tryFrom($value) !== null; } public function isLow(): bool { return $this === self::LOW; } public function isHigh(): bool { return $this === self::HIGH; } } app/Component/ES/UpdateProcessManager.php +12-9Lines changed: 12 additions & 9 deletions Original file line numberOriginal file lineDiff line numberDiff line change if ($selectionList->isEmpty()) { if ($selectionList->isEmpty()) { return false; return false; } } /** /** * A stale chunk will always be smaller than a regular chunk. * A stale chunk will always be smaller than a regular chunk. * That doesn't mean there aren't any other scheduled entities for processing * That doesn't mean there aren't any other scheduled entities for processing private function rescheduleThrottledEntities(SelectionList $selectionList): void private function rescheduleThrottledEntities(SelectionList $selectionList): void { { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $groups = $selectionList->getEntityListGroups(); $this->updateTarget, foreach ($groups as $eachGroup) { $selectionList->getNormalPriorityEntityId() $groupEntityIds = $selectionList->getEntityListItemsByGroup($eachGroup); ); if (! empty($groupEntityIds)) { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $this->updateTarget, entityType: $this->updateTarget, $selectionList->getHighPriorityEntityIds(), entityIds: $groupEntityIds, true priority: QueuePriorityEnum::tryFromString($eachGroup) ); ); } } } } } } app/Console/Commands/Elasticsearch/AsyncUpdateEsEntities.php +9-3Lines changed: 9 additions & 3 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Illuminate\\Support\\Str; use Illuminate\\Support\\Str; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Component\\ES\\UpdateProcessManager; use Jiminny\\Component\\ES\\UpdateProcessManager; use Jiminny\\Exceptions\\InvalidArgumentException; use Jiminny\\Exceptions\\InvalidArgumentException; use Jiminny\\Traits\\GracefullyStoppable; use Jiminny\\Traits\\GracefullyStoppable; Redis::set($gaugeLockName, true); Redis::set($gaugeLockName, true); Redis::expire($gaugeLockName, 60); Redis::expire($gaugeLockName, 60); $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::HIGH), ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update', $updateTarget), stat: sprintf('jiminny.%s-for-update', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::NORMAL), ); ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), stat: sprintf('jiminny.%s-for-update-low', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, true), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::LOW), ); ); } } app/Console/Commands/Elasticsearch/ResetAsyncElasticSearchCommand.php +5-1Lines changed: 5 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder; use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder; use Jiminny\\Component\\ES\\Processor\\Traits\\ValidateUpdateTargetTrait; use Jiminny\\Component\\ES\\Processor\\Traits\\ValidateUpdateTargetTrait; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Component\\ES\\Repositories\\EsResetRepositoryInterface; use Jiminny\\Component\\ES\\Repositories\\EsResetRepositoryInterface; use Jiminny\\Exceptions\\InvalidArgumentException; use Jiminny\\Exceptions\\InvalidArgumentException; use Jiminny\\Traits\\GracefullyStoppable; use Jiminny\\Traits\\GracefullyStoppable; private function getRemainingScheduledEntities(bool $printStatus = false): int private function getRemainingScheduledEntities(bool $printStatus = false): int { { $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget, true); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount( $this->updateTarget, QueuePriorityEnum::HIGH ); if ($printStatus) { if ($printStatus) { $this->line( $this->line(","depth":21,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"You said","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app/Component/ES/Listeners/UpdateMultipleTargetsListener.php","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"+2-1Lines changed: 2 additions & 1 deletion","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\\Component\\ES\\Listeners;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"namespace Jiminny\\Component\\ES\\Listeners;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\QueuePriorityEnum;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Contracts\\ES\\Events\\UpdateMultipleEntities;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Contracts\\ES\\Events\\UpdateMultipleEntities;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Psr\\Log\\LoggerInterface;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Psr\\Log\\LoggerInterface;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getUpdateTargetValue(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getUpdateTargetValue(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getEntities(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getEntities(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->isPriority()","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL,","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":");","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":");","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app/Component/ES/Listeners/UpdateSingleTargetListener.php","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"+9-1Lines changed: 9 additions & 1 deletion","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Actions\\TrackElasticSearchOperations;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Actions\\TrackElasticSearchOperations;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\QueuePriorityEnum;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Contracts\\ES\\Events\\UpdateSingleEntity;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Contracts\\ES\\Events\\UpdateSingleEntity;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Psr\\Log\\LoggerInterface;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Psr\\Log\\LoggerInterface;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"'entityId' => $event->getEntityId(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"'entityId' => $event->getEntityId(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"]);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"]);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/**","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* @important:","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* Synchronous event should eventually be deprecated.","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* Instant write operations are blocking and should be used sparingly.","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* It is much better in terms of performance to write 100 or 1000 documents at once,","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* and have one blocking reindex operation, instead of writing 10 documents synchronously.","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"*/","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"if ($event->isSyncEvent()) {","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"if ($event->isSyncEvent()) {","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$this->handleSyncEvent($event);","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$this->handleSyncEvent($event);","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AsyncUpdateElasticSearch::markEntityForUpdate(","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AsyncUpdateElasticSearch::markEntityForUpdate(","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getUpdateTargetValue(),","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getUpdateTargetValue(),","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getEntityId(),","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getEntityId(),","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->isPriority()","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL,","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":");","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":");","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app/Component/ES/Processor/Actions/UpsertDocumentsAction.php","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"+2-1Lines changed: 2 additions & 1 deletion","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Processor\\DTOs\\SimpleCollection;","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\DTOs\\SimpleCollection;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\ResponseEvaluator;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\ResponseEvaluator;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\QueuePriorityEnum;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Exceptions\\InvalidDataException;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Exceptions\\InvalidDataException;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Sentry\\Laravel\\Facade as Sentry;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Sentry\\Laravel\\Facade as Sentry;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AsyncUpdateElasticSearch::markEntityForUpdate(","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AsyncUpdateElasticSearch::markEntityForUpdate(","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"entityType: $this->updateTarget,","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"entityType: $this->updateTarget,","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"entityId: (int) $document->getId(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"entityId: (int) $document->getId(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"withPriority: true","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"priority: QueuePriorityEnum::HIGH,","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":");","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":");","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app/Component/ES/Processor/DTOs/SelectionList.php","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"+54-17Lines changed: 54 additions & 17 deletions","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Original file line numberOriginal file lineDiff line numberDiff line change","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"namespace Jiminny\\Component\\ES\\Processor\\DTOs;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"namespace Jiminny\\Component\\ES\\Processor\\DTOs;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\QueuePriorityEnum;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/**","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/**","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* A very basic and simple collection of entity IDs.","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* A very basic and simple collection of entity IDs.","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"*/","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"*/","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"class SelectionList","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"class SelectionList","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function __construct(","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private const int DEFAULT_CHUNK = 200;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private readonly array $priorityEntityIdList = [],","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private readonly array $normalEntityIdList = [],","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private int $chunkSize = self::DEFAULT_CHUNK;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private readonly bool $isStaleChunkSelected = false,","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private bool $isStaleChunkSelected = false;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private readonly int $chunkSize = 200,","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private array $selectedEntityIds = [];","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":") {","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"// Do nothing","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function setChunkSize(int $chunkSize): void","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$this->chunkSize = $chunkSize;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function getAllIds(): array","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function markStale(): void","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"return array_merge($this->priorityEntityIdList, $this->normalEntityIdList);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$this->isStaleChunkSelected = true;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function count(): int","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function addEntityList(string|QueuePriorityEnum $priority, array $entityIds): void","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"return count($this->priorityEntityIdList) + count($this->normalEntityIdList);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$priorityKey = $this->normalisePriority($priority);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"if (! array_key_exists($priorityKey, $this->selectedEntityIds)) {","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$this->selectedEntityIds[$priorityKey] = [];","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$this->selectedEntityIds[$priorityKey] = array_merge($this->selectedEntityIds[$priorityKey], $entityIds);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function isEmpty(): bool","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/**","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* @return string[]","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"*/","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function getEntityListGroups(): array","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"return empty($this->priorityEntityIdList) && empty($this->normalEntityIdList);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"return array_keys($this->selectedEntityIds);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function getHighPriorityEntityIds(): array","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function getEntityListItemsByGroup(string|QueuePriorityEnum $priority): array","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"return $this->priorityEntityIdList;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$priorityKey = $this->normalisePriority($priority);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"return $this->selectedEntityIds[$priorityKey] ?? [];","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function getNormalPriorityEntityId(): array","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function getAllIds(): array","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"return $this->normalEntityIdList;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$allIds = [];","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"foreach ($this->selectedEntityIds as $entityIds) {","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$allIds = array_merge($allIds, $entityIds);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"return $allIds;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function count(): int","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"return array_sum(","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"array_map('count', $this->selectedEntityIds)","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":");","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function isEmpty(): bool","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"return $this->count() === 0;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function isStaleChunkSelected(): bool","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function isStaleChunkSelected(): bool","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"return $this->count() >= $this->chunkSize;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"return $this->count() >= $this->chunkSize;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private function normalisePriority(string|QueuePriorityEnum $priority): string","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"return $priority instanceof QueuePriorityEnum ? $priority->value : $priority;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app/Component/ES/Processor/Traits/SelectEntityListTrait.php","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"+27-4Lines changed: 27 additions & 4 deletions","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Original file line numberOriginal file lineDiff line numberDiff line change","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Illuminate\\Support\\Facades\\Log;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Illuminate\\Support\\Facades\\Log;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"}]...
|
-4656605998239323170
|
-1144453838252598114
|
click
|
accessibility
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
Close tab
New Tab
Customize sidebar
Close Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
AI Chat settings
Close
WORK, Google Account: [EMAIL]
Main menu
New chat
Gemini
New Chat
Open menu for conversation actions.
Conversation with Gemini
Conversation with Gemini
Show the uploaded image in a lightbox
Copy prompt
You said Make a PR of changes Find potential issues and bottlenecks
You said
Make a PR of changes Find potential issues and bottlenecks
Listen
Show thinking
Gemini said
Gemini said
I can see you've uploaded a screenshot of a code diff, likely from a version control system given the red and green highlights. I would love to help you review the changes, spot bottlenecks, and help you draft a Pull Request.
However,
the image resolution is far too low for me to read.
It appears to be a completely zoomed-out view where the code has been reduced to tiny, illegible pixels. Because of this, I cannot extract any text or logic to analyze.
How You Can Share the Code
How You Can Share the Code
To help me review your code effectively, please try one of the following:
Paste the text directly:
Copy the specific code blocks (both the old and new versions if possible) and paste them directly into our chat.
Upload the files:
If the changes are extensive, you can upload the raw text or code files.
Take high-resolution screenshots:
If you must use images, take closer, readable screenshots of the specific functions or methods you want me to review.
Once you provide the readable code, I can dive right in to identify potential bugs, assess performance bottlenecks, and help you summarize the changes for your PR!
Good response
Bad response
Share & export
Copy
Show more options
Copy prompt
Edit
You said app/Component/ES/Listeners/UpdateMultipleTargetsListener.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\Component\ES\Listeners; namespace Jiminny\Component\ES\Listeners; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Contracts\ES\Events\UpdateMultipleEntities; use Jiminny\Contracts\ES\Events\UpdateMultipleEntities; use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface; AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntities(), $event->getEntities(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } } } app/Component/ES/Listeners/UpdateSingleTargetListener.php +9-1Lines changed: 9 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Actions\TrackElasticSearchOperations; use Jiminny\Component\ES\Actions\TrackElasticSearchOperations; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Contracts\ES\Events\UpdateSingleEntity; use Jiminny\Contracts\ES\Events\UpdateSingleEntity; use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface; 'entityId' => $event->getEntityId(), 'entityId' => $event->getEntityId(), ]); ]); /** * @important: * Synchronous event should eventually be deprecated. * Instant write operations are blocking and should be used sparingly. * It is much better in terms of performance to write 100 or 1000 documents at once, * and have one blocking reindex operation, instead of writing 10 documents synchronously. */ if ($event->isSyncEvent()) { if ($event->isSyncEvent()) { $this->handleSyncEvent($event); $this->handleSyncEvent($event); AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntityId(), $event->getEntityId(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } app/Component/ES/Processor/Actions/UpsertDocumentsAction.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SimpleCollection; use Jiminny\Component\ES\Processor\DTOs\SimpleCollection; use Jiminny\Component\ES\Processor\ResponseEvaluator; use Jiminny\Component\ES\Processor\ResponseEvaluator; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Exceptions\InvalidDataException; use Jiminny\Exceptions\InvalidDataException; use Sentry\Laravel\Facade as Sentry; use Sentry\Laravel\Facade as Sentry; AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( entityType: $this->updateTarget, entityType: $this->updateTarget, entityId: (int) $document->getId(), entityId: (int) $document->getId(), withPriority: true priority: QueuePriorityEnum::HIGH, ); ); } } app/Component/ES/Processor/DTOs/SelectionList.php +54-17Lines changed: 54 additions & 17 deletions Original file line numberOriginal file lineDiff line numberDiff line change namespace Jiminny\Component\ES\Processor\DTOs; namespace Jiminny\Component\ES\Processor\DTOs; use Jiminny\Component\ES\QueuePriorityEnum; /** /** * A very basic and simple collection of entity IDs. * A very basic and simple collection of entity IDs. */ */ class SelectionList class SelectionList { { public function __construct( private const int DEFAULT_CHUNK = 200; private readonly array $priorityEntityIdList = [], private readonly array $normalEntityIdList = [], private int $chunkSize = self::DEFAULT_CHUNK; private readonly bool $isStaleChunkSelected = false, private bool $isStaleChunkSelected = false; private readonly int $chunkSize = 200, private array $selectedEntityIds = []; ) { // Do nothing public function setChunkSize(int $chunkSize): void { $this->chunkSize = $chunkSize; } } public function getAllIds(): array public function markStale(): void { { return array_merge($this->priorityEntityIdList, $this->normalEntityIdList); $this->isStaleChunkSelected = true; } } public function count(): int public function addEntityList(string|QueuePriorityEnum $priority, array $entityIds): void { { return count($this->priorityEntityIdList) + count($this->normalEntityIdList); $priorityKey = $this->normalisePriority($priority); if (! array_key_exists($priorityKey, $this->selectedEntityIds)) { $this->selectedEntityIds[$priorityKey] = []; } $this->selectedEntityIds[$priorityKey] = array_merge($this->selectedEntityIds[$priorityKey], $entityIds); } } public function isEmpty(): bool /** * @return string[] */ public function getEntityListGroups(): array { { return empty($this->priorityEntityIdList) && empty($this->normalEntityIdList); return array_keys($this->selectedEntityIds); } } public function getHighPriorityEntityIds(): array public function getEntityListItemsByGroup(string|QueuePriorityEnum $priority): array { { return $this->priorityEntityIdList; $priorityKey = $this->normalisePriority($priority); return $this->selectedEntityIds[$priorityKey] ?? []; } } public function getNormalPriorityEntityId(): array public function getAllIds(): array { { return $this->normalEntityIdList; $allIds = []; foreach ($this->selectedEntityIds as $entityIds) { $allIds = array_merge($allIds, $entityIds); } return $allIds; } public function count(): int { return array_sum( array_map('count', $this->selectedEntityIds) ); } public function isEmpty(): bool { return $this->count() === 0; } } public function isStaleChunkSelected(): bool public function isStaleChunkSelected(): bool { { return $this->count() >= $this->chunkSize; return $this->count() >= $this->chunkSize; } } private function normalisePriority(string|QueuePriorityEnum $priority): string { return $priority instanceof QueuePriorityEnum ? $priority->value : $priority; } } } app/Component/ES/Processor/Traits/SelectEntityListTrait.php +27-4Lines changed: 27 additions & 4 deletions Original file line numberOriginal file lineDiff line numberDiff line change use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; /** /** * Build the correct source list name for the type of entity and priority * Build the correct source list name for the type of entity and priority */ */ trait SelectEntityListTrait trait SelectEntityListTrait { { /** * Highest priority queue for data requiring near-instant availability. * Very few entities should be added here, only when absolutely necessary. */ private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; /** * Normal priority queue for normal application operations. * Almost all update events should pass through this queue */ private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; protected static function selectTargetList(string $entityType, bool $withPriority = false): string /** { * Nonblocking low priority queue. This queue will be consumed only when there is nothing * with higher priority. * * This queue will be used for operations such as es:reset-async */ private const string ENTITIES_LOW_PRIORITIES_LIST = '%s-for-update-low'; protected static function selectTargetList( string $entityType, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { if (! in_array($entityType, UpdateTarget::allowedTargets())) { if (! in_array($entityType, UpdateTarget::allowedTargets())) { throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); } } if ($withPriority) { if ($priority->isHigh()) { Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); } } if ($priority->isLow()) { return sprintf(self::ENTITIES_LOW_PRIORITIES_LIST, $entityType); } return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); } } } } app/Component/ES/Processor/TargetEntitiesSelector.php +26-21Lines changed: 26 additions & 21 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SelectionList; use Jiminny\Component\ES\Processor\DTOs\SelectionList; use Jiminny\Component\ES\Processor\Traits\ExtractIdsTrait; use Jiminny\Component\ES\Processor\Traits\ExtractIdsTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\QueuePriorityEnum; /** /** * This class supplies a list of entities pending an update. * This class supplies a list of entities pending an update. public function select(): SelectionList public function select(): SelectionList { { $staleWorkEntityIds = $this->getStaleChunk(); $selectionList = new SelectionList(); $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $staleWorkEntityIds = $this->getStaleChunk(); if (count($staleWorkEntityIds) > 0) { if (count($staleWorkEntityIds) > 0) { return new SelectionList( /** priorityEntityIdList: $staleWorkEntityIds, * Stale chunks are treated as high priority isStaleChunkSelected: true, */ chunkSize: ChunkSize::getStaleChunkSize($this->updateTarget), $selectionList->markStale(); ); $selectionList->addEntityList(QueuePriorityEnum::HIGH, $staleWorkEntityIds); $selectionList->setChunkSize(ChunkSize::getStaleChunkSize($this->updateTarget)); return $selectionList; } } $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $selectionList->setChunkSize($mainChunkSize); $priorityEntityIdsList = $this->extractIdsFromSet( $priorityEntityIdsList = $this->extractIds(QueuePriorityEnum::HIGH, $mainChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, true), $selectionList->addEntityList(QueuePriorityEnum::HIGH, $priorityEntityIdsList); $mainChunkSize, ); $normalEntityIdsList = []; $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); if ($normalEntityChunkSize > 0) { if ($normalEntityChunkSize > 0) { $normalEntityIdsList = $this->extractIdsFromSet( $normalEntityIdsList = $this->extractIds(QueuePriorityEnum::NORMAL, $normalEntityChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, false), $selectionList->addEntityList(QueuePriorityEnum::NORMAL, $normalEntityIdsList); $normalEntityChunkSize ); } } return new SelectionList( return $selectionList; priorityEntityIdList: $priorityEntityIdsList, normalEntityIdList: $normalEntityIdsList, chunkSize: $mainChunkSize ); } } private function getStaleChunk(): array private function getStaleChunk(): array return []; return []; } } private function extractIds(QueuePriorityEnum $priority, int $chunkSize): array { return $this->extractIdsFromSet( AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, $priority), $chunkSize ); } } } app/Component/ES/AsyncUpdateElasticSearch.php +17-10Lines changed: 17 additions & 10 deletions Original file line numberOriginal file lineDiff line numberDiff line change * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * and other activity related data * and other activity related data */ */ public static function markEntityForUpdate(string $entityType, int $entityId, bool $withPriority = false): void public static function markEntityForUpdate( { string $entityType, $targetList = self::selectTargetList($entityType, $withPriority); int $entityId, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { $targetList = self::selectTargetList($entityType, $priority); Redis::sadd($targetList, $entityId); Redis::sadd($targetList, $entityId); Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ 'entityType' => $entityType, 'entityType' => $entityType, 'entityId' => $entityId, 'entityId' => $entityId, 'collectionKey' => $targetList, 'collectionKey' => $targetList, 'withPriority' => $withPriority, 'priority' => $priority->value, ]); ]); } } public static function bulkMarkEntitiesForUpdate( public static function bulkMarkEntitiesForUpdate( string $entityType, string $entityType, array $entityIds, array $entityIds, bool $withPriority = false QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { ): void { if (empty($entityIds)) { if (empty($entityIds)) { return; return; } } $targetList = self::selectTargetList($entityType, $withPriority); $targetList = self::selectTargetList($entityType, $priority); Redis::saddarray($targetList, $entityIds); Redis::saddarray($targetList, $entityIds); } } * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Takes priority into consideration. * Takes priority into consideration. */ */ public static function getEntitiesSourceList(string $updateTarget, $priority = false): string public static function getEntitiesSourceList( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { return self::selectTargetList($updateTarget, $priority); return self::selectTargetList($updateTarget, $priority); } } /** /** * Externally called helper methods * Externally called helper methods * - count and flush * - count and flush */ */ public static function getEntitiesListCount(string $updateTarget, $priority = false): int public static function getEntitiesListCount( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): int { $targetList = self::selectTargetList($updateTarget, $priority); $targetList = self::selectTargetList($updateTarget, $priority); return Redis::scard($targetList); return Redis::scard($targetList); app/Component/ES/QueuePriorityEnum.php +40Lines changed: 40 additions & 0 deletions Original file line numberOriginal file lineDiff line numberDiff line change <?php declare(strict_types=1); namespace Jiminny\Component\ES; use Jiminny\Exceptions\InvalidArgumentException; enum QueuePriorityEnum: string { case HIGH = 'high'; case NORMAL = 'normal'; case LOW = 'low'; public static function tryFromString(string $value): self { if (! self::isValid($value)) { throw new InvalidArgumentException( sprintf('Invalid queue priority "%s" selected', $value) ); } return self::tryFrom($value); } public static function isValid(string $value): bool { return self::tryFrom($value) !== null; } public function isLow(): bool { return $this === self::LOW; } public function isHigh(): bool { return $this === self::HIGH; } } app/Component/ES/UpdateProcessManager.php +12-9Lines changed: 12 additions & 9 deletions Original file line numberOriginal file lineDiff line numberDiff line change if ($selectionList->isEmpty()) { if ($selectionList->isEmpty()) { return false; return false; } } /** /** * A stale chunk will always be smaller than a regular chunk. * A stale chunk will always be smaller than a regular chunk. * That doesn't mean there aren't any other scheduled entities for processing * That doesn't mean there aren't any other scheduled entities for processing private function rescheduleThrottledEntities(SelectionList $selectionList): void private function rescheduleThrottledEntities(SelectionList $selectionList): void { { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $groups = $selectionList->getEntityListGroups(); $this->updateTarget, foreach ($groups as $eachGroup) { $selectionList->getNormalPriorityEntityId() $groupEntityIds = $selectionList->getEntityListItemsByGroup($eachGroup); ); if (! empty($groupEntityIds)) { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $this->updateTarget, entityType: $this->updateTarget, $selectionList->getHighPriorityEntityIds(), entityIds: $groupEntityIds, true priority: QueuePriorityEnum::tryFromString($eachGroup) ); ); } } } } } } app/Console/Commands/Elasticsearch/AsyncUpdateEsEntities.php +9-3Lines changed: 9 additions & 3 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Illuminate\Support\Str; use Illuminate\Support\Str; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Component\ES\UpdateProcessManager; use Jiminny\Component\ES\UpdateProcessManager; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Traits\GracefullyStoppable; use Jiminny\Traits\GracefullyStoppable; Redis::set($gaugeLockName, true); Redis::set($gaugeLockName, true); Redis::expire($gaugeLockName, 60); Redis::expire($gaugeLockName, 60); $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::HIGH), ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update', $updateTarget), stat: sprintf('jiminny.%s-for-update', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::NORMAL), ); ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), stat: sprintf('jiminny.%s-for-update-low', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, true), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::LOW), ); ); } } app/Console/Commands/Elasticsearch/ResetAsyncElasticSearchCommand.php +5-1Lines changed: 5 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\Traits\ValidateUpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\ValidateUpdateTargetTrait; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Component\ES\Repositories\EsResetRepositoryInterface; use Jiminny\Component\ES\Repositories\EsResetRepositoryInterface; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Traits\GracefullyStoppable; use Jiminny\Traits\GracefullyStoppable; private function getRemainingScheduledEntities(bool $printStatus = false): int private function getRemainingScheduledEntities(bool $printStatus = false): int { { $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget, true); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount( $this->updateTarget, QueuePriorityEnum::HIGH ); if ($printStatus) { if ($printStatus) { $this->line( $this->line(
You said
app/Component/ES/Listeners/UpdateMultipleTargetsListener.php
+2-1Lines changed: 2 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\Component\ES\Listeners;
namespace Jiminny\Component\ES\Listeners;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\QueuePriorityEnum;
use Jiminny\Contracts\ES\Events\UpdateMultipleEntities;
use Jiminny\Contracts\ES\Events\UpdateMultipleEntities;
use Psr\Log\LoggerInterface;
use Psr\Log\LoggerInterface;
AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(
AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(
$event->getUpdateTargetValue(),
$event->getUpdateTargetValue(),
$event->getEntities(),
$event->getEntities(),
$event->isPriority()
$event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL,
);
);
}
}
}
}
app/Component/ES/Listeners/UpdateSingleTargetListener.php
+9-1Lines changed: 9 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Actions\TrackElasticSearchOperations;
use Jiminny\Component\ES\Actions\TrackElasticSearchOperations;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\Processor\EntityQueryBuilder;
use Jiminny\Component\ES\Processor\EntityQueryBuilder;
use Jiminny\Component\ES\QueuePriorityEnum;
use Jiminny\Contracts\ES\Events\UpdateSingleEntity;
use Jiminny\Contracts\ES\Events\UpdateSingleEntity;
use Psr\Log\LoggerInterface;
use Psr\Log\LoggerInterface;
'entityId' => $event->getEntityId(),
'entityId' => $event->getEntityId(),
]);
]);
/**
* @important:
* Synchronous event should eventually be deprecated.
* Instant write operations are blocking and should be used sparingly.
* It is much better in terms of performance to write 100 or 1000 documents at once,
* and have one blocking reindex operation, instead of writing 10 documents synchronously.
*/
if ($event->isSyncEvent()) {
if ($event->isSyncEvent()) {
$this->handleSyncEvent($event);
$this->handleSyncEvent($event);
AsyncUpdateElasticSearch::markEntityForUpdate(
AsyncUpdateElasticSearch::markEntityForUpdate(
$event->getUpdateTargetValue(),
$event->getUpdateTargetValue(),
$event->getEntityId(),
$event->getEntityId(),
$event->isPriority()
$event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL,
);
);
}
}
app/Component/ES/Processor/Actions/UpsertDocumentsAction.php
+2-1Lines changed: 2 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SimpleCollection;
use Jiminny\Component\ES\Processor\DTOs\SimpleCollection;
use Jiminny\Component\ES\Processor\ResponseEvaluator;
use Jiminny\Component\ES\Processor\ResponseEvaluator;
use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait;
use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait;
use Jiminny\Component\ES\QueuePriorityEnum;
use Jiminny\Exceptions\InvalidDataException;
use Jiminny\Exceptions\InvalidDataException;
use Sentry\Laravel\Facade as Sentry;
use Sentry\Laravel\Facade as Sentry;
AsyncUpdateElasticSearch::markEntityForUpdate(
AsyncUpdateElasticSearch::markEntityForUpdate(
entityType: $this->updateTarget,
entityType: $this->updateTarget,
entityId: (int) $document->getId(),
entityId: (int) $document->getId(),
withPriority: true
priority: QueuePriorityEnum::HIGH,
);
);
}
}
app/Component/ES/Processor/DTOs/SelectionList.php
+54-17Lines changed: 54 additions & 17 deletions
Original file line numberOriginal file lineDiff line numberDiff line change
namespace Jiminny\Component\ES\Processor\DTOs;
namespace Jiminny\Component\ES\Processor\DTOs;
use Jiminny\Component\ES\QueuePriorityEnum;
/**
/**
* A very basic and simple collection of entity IDs.
* A very basic and simple collection of entity IDs.
*/
*/
class SelectionList
class SelectionList
{
{
public function __construct(
private const int DEFAULT_CHUNK = 200;
private readonly array $priorityEntityIdList = [],
private readonly array $normalEntityIdList = [],
private int $chunkSize = self::DEFAULT_CHUNK;
private readonly bool $isStaleChunkSelected = false,
private bool $isStaleChunkSelected = false;
private readonly int $chunkSize = 200,
private array $selectedEntityIds = [];
) {
// Do nothing
public function setChunkSize(int $chunkSize): void
{
$this->chunkSize = $chunkSize;
}
}
public function getAllIds(): array
public function markStale(): void
{
{
return array_merge($this->priorityEntityIdList, $this->normalEntityIdList);
$this->isStaleChunkSelected = true;
}
}
public function count(): int
public function addEntityList(string|QueuePriorityEnum $priority, array $entityIds): void
{
{
return count($this->priorityEntityIdList) + count($this->normalEntityIdList);
$priorityKey = $this->normalisePriority($priority);
if (! array_key_exists($priorityKey, $this->selectedEntityIds)) {
$this->selectedEntityIds[$priorityKey] = [];
}
$this->selectedEntityIds[$priorityKey] = array_merge($this->selectedEntityIds[$priorityKey], $entityIds);
}
}
public function isEmpty(): bool
/**
* @return string[]
*/
public function getEntityListGroups(): array
{
{
return empty($this->priorityEntityIdList) && empty($this->normalEntityIdList);
return array_keys($this->selectedEntityIds);
}
}
public function getHighPriorityEntityIds(): array
public function getEntityListItemsByGroup(string|QueuePriorityEnum $priority): array
{
{
return $this->priorityEntityIdList;
$priorityKey = $this->normalisePriority($priority);
return $this->selectedEntityIds[$priorityKey] ?? [];
}
}
public function getNormalPriorityEntityId(): array
public function getAllIds(): array
{
{
return $this->normalEntityIdList;
$allIds = [];
foreach ($this->selectedEntityIds as $entityIds) {
$allIds = array_merge($allIds, $entityIds);
}
return $allIds;
}
public function count(): int
{
return array_sum(
array_map('count', $this->selectedEntityIds)
);
}
public function isEmpty(): bool
{
return $this->count() === 0;
}
}
public function isStaleChunkSelected(): bool
public function isStaleChunkSelected(): bool
{
{
return $this->count() >= $this->chunkSize;
return $this->count() >= $this->chunkSize;
}
}
private function normalisePriority(string|QueuePriorityEnum $priority): string
{
return $priority instanceof QueuePriorityEnum ? $priority->value : $priority;
}
}
}
app/Component/ES/Processor/Traits/SelectEntityListTrait.php
+27-4Lines changed: 27 additions & 4 deletions
Original file line numberOriginal file lineDiff line numberDiff line change
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Log;...
|
55705
|
NULL
|
NULL
|
NULL
|
|
55707
|
1935
|
6
|
2026-05-19T06:44:11.658729+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779173051658_m2.jpg...
|
Firefox
|
NULL
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
FirefoxVIewPlatform Sprint 4 Q2 - Platform TeJY-20 FirefoxVIewPlatform Sprint 4 Q2 - Platform TeJY-20725 add HS rate limit handlJY-20808 low priority indexing+ New TabMistorbookmarksProtllesToolsWindowmelp• github.com/itminny/app/pull/12082/changes#diff-61654edeebd72388bddd97cafcac889a2d106f54bb484a719d4067878bb9b011• Goodle geminiGeminiPHP• Bottleneck: count() is frequently called (e.g., inside (isEmpty() , isStaleChunkSelected() .and potentially loops). Running array_map and array_sum every single time createsunnecessary micro-overhead.• Optimization: Maintain a private int $totalCount = 0; property. Increment it insideaddEntityList() : $this-›totalCount += count(SentityIds); . Then your count()method simply becomes return $this->totalCount;2. Redis Network BottleneckIn TargetEntitiesSelector::sellect(), vou are doina sequential round-trios to Redis for eachqueue:1. getStaleChunk() (Network trip)extractidsQueuePrioritvEnum: •HIGh...) Network trio)3. extractIds(QueuePriorityEnum: : NORMAL...› (Network trip)• Optimization (Future): While this PR maintains existing behavior, sequential Redis calls blockexecution. If queue processing speed becomes an issue, consider migrating these extractioncommands to a Redis Lua script or using Pipeline/Transactions to fetch multiple queues in asingle network round-trip.Are you confident that all external calls to methods likeAsvncUpdateFlosticSearch::markEntitvForUodate across the entire codebase have been uodatedto pass the new Enum instead of a boolean, or should we add a temporary fallback to support bothtypes during the transition?© Enter a prompt for GeminiProvYour Jiminny chats aren't used to improve our models. Gemini is Al. It can make mistakes, so double check it. Your privacy & GeminiSummarize page87 OpenJY-20808 low orioritv indexing queue #12082|All commits -Vasil-Jiminny wants to merge 36 commits into master from JY-20808-low-priority-indexing-queue E~ app/Component/ES/Processor/DTOs/SelectionList.php *Q Filter files...~ E app~ 5 Component/ESv & ListenersE UpdateMultipleTargetsListen...E UpdateSingleTargetListener....• • Processor~ & ActionsE UpsertDocumentsAction.phpv • DTOsE SelectionList.php• & TraitsSelectEntityListTrait.php# TargetEntitiesSelector.phpAsyncUpdateElasticSearch.php# QueuePriorityEnum.ohp# UpdateProcessManager.phpv Console/Commands/Elasticsear…# AsyncUpdateEsEntities.phpE ResetAsyncElasticSearchCom.> Ea tests/Unit/Component/ES|*A very Dasic and simple collection or encity Lus.class SelectionListpubuic tunction constructlprivate readonly array $priorityEntityldList = U,private readonly array $normalEntityIdList = [],private readonly bool sisStaleChunkSelected = false.private readonly int $chunkSize = 200,// Do nothing21 -public function aetAllIds(): arrav23 -return array merae(sthis->orioritvEntitvidList. sthis->normalEntitvidList):public function count(): int28-return count(sthis->orioritvEntitvidList) + count(Sthis->normalEntitvIdList):31 -33 -oublic function isEmotv(): boollreturn empty(Sthis->priorityEntityIdList) && empty(Sthis->normalEntityIdList);public function cetHiahPrioritvEntitvids: arrav"Dally - Platrorm • In 1m* 100% C4 &• Tue 19 May 9:44:11• 4 18 viewed |• Awaiting approvalSubmit review+54 -17 0002Viewed+ use Jiminny ComoonentES OueuePrior1tvEnum:* A very basic and slepte collection of entity 1oclass SelectionList14 +private const int DEFAULT_CHUNK = 200;private int $chunkSize = self::DEFAULT_CHUNK;private bool SisStaleChunkSelected = false:private array $selectedEntityIds = [];public function setChunkSize(int $chunkSize): voidSthis->chunkSize = $chunkSize;25 +public function markStalel): void27 +Sthis->isStaleChunkSelected = true:30 +public function addEntityList(string|QueuePriorityEnum Spriority, array SentityIds):voidSorioritvKev = Sthis->normalisePrioritv(Sorioritv):if (! arrav kev exists(Sorioritvkev. Sthis->selectedEntitvIds)) {$this->selectedEntityIds[$priorityKey] = []:sthis->selectedEntitvids Sorioritvkev = arrav merae(Sthis->selectedEntityIds($priorityKey], SentityIds);* @return string(]public function getEntityListGroups(): array46 +return array_keys(Sthis->selectedEntityIds);public function aetEntitvListitemsBvGrouo(strina|OueuePrioritvEnum Soriority): arrav...
|
NULL
|
-2967223941117549361
|
NULL
|
click
|
ocr
|
NULL
|
FirefoxVIewPlatform Sprint 4 Q2 - Platform TeJY-20 FirefoxVIewPlatform Sprint 4 Q2 - Platform TeJY-20725 add HS rate limit handlJY-20808 low priority indexing+ New TabMistorbookmarksProtllesToolsWindowmelp• github.com/itminny/app/pull/12082/changes#diff-61654edeebd72388bddd97cafcac889a2d106f54bb484a719d4067878bb9b011• Goodle geminiGeminiPHP• Bottleneck: count() is frequently called (e.g., inside (isEmpty() , isStaleChunkSelected() .and potentially loops). Running array_map and array_sum every single time createsunnecessary micro-overhead.• Optimization: Maintain a private int $totalCount = 0; property. Increment it insideaddEntityList() : $this-›totalCount += count(SentityIds); . Then your count()method simply becomes return $this->totalCount;2. Redis Network BottleneckIn TargetEntitiesSelector::sellect(), vou are doina sequential round-trios to Redis for eachqueue:1. getStaleChunk() (Network trip)extractidsQueuePrioritvEnum: •HIGh...) Network trio)3. extractIds(QueuePriorityEnum: : NORMAL...› (Network trip)• Optimization (Future): While this PR maintains existing behavior, sequential Redis calls blockexecution. If queue processing speed becomes an issue, consider migrating these extractioncommands to a Redis Lua script or using Pipeline/Transactions to fetch multiple queues in asingle network round-trip.Are you confident that all external calls to methods likeAsvncUpdateFlosticSearch::markEntitvForUodate across the entire codebase have been uodatedto pass the new Enum instead of a boolean, or should we add a temporary fallback to support bothtypes during the transition?© Enter a prompt for GeminiProvYour Jiminny chats aren't used to improve our models. Gemini is Al. It can make mistakes, so double check it. Your privacy & GeminiSummarize page87 OpenJY-20808 low orioritv indexing queue #12082|All commits -Vasil-Jiminny wants to merge 36 commits into master from JY-20808-low-priority-indexing-queue E~ app/Component/ES/Processor/DTOs/SelectionList.php *Q Filter files...~ E app~ 5 Component/ESv & ListenersE UpdateMultipleTargetsListen...E UpdateSingleTargetListener....• • Processor~ & ActionsE UpsertDocumentsAction.phpv • DTOsE SelectionList.php• & TraitsSelectEntityListTrait.php# TargetEntitiesSelector.phpAsyncUpdateElasticSearch.php# QueuePriorityEnum.ohp# UpdateProcessManager.phpv Console/Commands/Elasticsear…# AsyncUpdateEsEntities.phpE ResetAsyncElasticSearchCom.> Ea tests/Unit/Component/ES|*A very Dasic and simple collection or encity Lus.class SelectionListpubuic tunction constructlprivate readonly array $priorityEntityldList = U,private readonly array $normalEntityIdList = [],private readonly bool sisStaleChunkSelected = false.private readonly int $chunkSize = 200,// Do nothing21 -public function aetAllIds(): arrav23 -return array merae(sthis->orioritvEntitvidList. sthis->normalEntitvidList):public function count(): int28-return count(sthis->orioritvEntitvidList) + count(Sthis->normalEntitvIdList):31 -33 -oublic function isEmotv(): boollreturn empty(Sthis->priorityEntityIdList) && empty(Sthis->normalEntityIdList);public function cetHiahPrioritvEntitvids: arrav"Dally - Platrorm • In 1m* 100% C4 &• Tue 19 May 9:44:11• 4 18 viewed |• Awaiting approvalSubmit review+54 -17 0002Viewed+ use Jiminny ComoonentES OueuePrior1tvEnum:* A very basic and slepte collection of entity 1oclass SelectionList14 +private const int DEFAULT_CHUNK = 200;private int $chunkSize = self::DEFAULT_CHUNK;private bool SisStaleChunkSelected = false:private array $selectedEntityIds = [];public function setChunkSize(int $chunkSize): voidSthis->chunkSize = $chunkSize;25 +public function markStalel): void27 +Sthis->isStaleChunkSelected = true:30 +public function addEntityList(string|QueuePriorityEnum Spriority, array SentityIds):voidSorioritvKev = Sthis->normalisePrioritv(Sorioritv):if (! arrav kev exists(Sorioritvkev. Sthis->selectedEntitvIds)) {$this->selectedEntityIds[$priorityKey] = []:sthis->selectedEntitvids Sorioritvkev = arrav merae(Sthis->selectedEntityIds($priorityKey], SentityIds);* @return string(]public function getEntityListGroups(): array46 +return array_keys(Sthis->selectedEntityIds);public function aetEntitvListitemsBvGrouo(strina|OueuePrioritvEnum Soriority): arrav...
|
55704
|
NULL
|
NULL
|
NULL
|
|
55708
|
1935
|
7
|
2026-05-19T06:44:16.672640+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779173056672_m2.jpg...
|
Firefox
|
Meet - Daily - Platform — Work
|
1
|
meet.google.com/agt-teir-cwt?authuser=lukas.kovali meet.google.com/agt-teir-cwt?authuser=lukas.kovalik%40jiminny.com...
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
FirefoxEditVIewHistorybookmarksProtllesToolsWindow FirefoxEditVIewHistorybookmarksProtllesToolsWindowHelpMeet - Daily - Platform+ New Tab~ Google Gemini1 MeetLukas KovalikI LakyLak bos...Ask GeminiSummarize page"Dally - Platrorm • In 1m100% C4 & • Tue 19 May 9:44:[EMAIL] - Platformin 1 minuteUse Gemini to take notesJoin nowOther ways to join4) System Defa...O FaceTime HD….[g Backgrounds….Cecens to malaing ia pfioen s. Jying Ask Gemini weerding or store meeting data. The meeting...
|
NULL
|
-4624212258491129622
|
NULL
|
click
|
ocr
|
NULL
|
FirefoxEditVIewHistorybookmarksProtllesToolsWindow FirefoxEditVIewHistorybookmarksProtllesToolsWindowHelpMeet - Daily - Platform+ New Tab~ Google Gemini1 MeetLukas KovalikI LakyLak bos...Ask GeminiSummarize page"Dally - Platrorm • In 1m100% C4 & • Tue 19 May 9:44:[EMAIL] - Platformin 1 minuteUse Gemini to take notesJoin nowOther ways to join4) System Defa...O FaceTime HD….[g Backgrounds….Cecens to malaing ia pfioen s. Jying Ask Gemini weerding or store meeting data. The meeting...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
55709
|
1934
|
5
|
2026-05-19T06:44:23.667689+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779173063667_m1.jpg...
|
Firefox
|
Meet - Daily - Platform — Work
|
1
|
meet.google.com/agt-teir-cwt?authuser=lukas.kovali meet.google.com/agt-teir-cwt?authuser=lukas.kovalik%40jiminny.com...
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Meet - Daily - Platform
Close tab
New Tab
Open Goo Meet - Daily - Platform
Close tab
New Tab
Open Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
Customize sidebar
Return to home screen
[EMAIL]
Switch account
Switch account
Lukas Kovalik
More options
Turn off microphone
Turn off camera
Turn on background blur
Microphone: LakyLak bose qc35 II
Speaker: System Default Speaker Device
Camera: FaceTime HD Camera
Backgrounds and effects
Daily - Platform
Daily - Platform
in 1 minute
Use Gemini to take notes Share notes and transcript
Use Gemini to take notes
Share notes and transcript
Start
Start
Join now
Join now
Other ways to join
Gemini is available in Meet as your personal in-meeting assistant. It can analyze conversation via temporary access to meeting captions. Using Ask Gemini won't create a recording or store meeting data. The meeting host can turn it off.
Learn more
Learn more
Your camera is on. Your microphone is on.
Background is now replaced...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Meet - Daily - Platform","depth":4,"bounds":{"left":0.0,"top":0.072222225,"width":0.16631944,"height":0.045555554},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.0013888889,"top":0.072222225,"width":0.010416667,"height":0.016666668},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New Tab","depth":4,"bounds":{"left":0.005902778,"top":0.12,"width":0.022222223,"height":0.035555556},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open Google Gemini (⌃X)","depth":6,"bounds":{"left":0.0,"top":0.7977778,"width":0.033680554,"height":0.043333333},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Tabs from other devices","depth":6,"bounds":{"left":0.0,"top":0.8411111,"width":0.033680554,"height":0.038333334},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"bounds":{"left":0.0,"top":0.8794444,"width":0.033680554,"height":0.03888889},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"bounds":{"left":0.0,"top":0.91833335,"width":0.033680554,"height":0.038333334},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"bounds":{"left":0.0,"top":0.95666665,"width":0.033680554,"height":0.043333333},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Return to home screen","depth":10,"bounds":{"left":0.052430555,"top":0.09,"width":0.072916664,"height":0.044444446},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"lukas.kovalik@jiminny.com","depth":12,"bounds":{"left":0.846875,"top":0.09166667,"width":0.11631945,"height":0.018333333},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Switch account","depth":11,"bounds":{"left":0.89375,"top":0.11,"width":0.061805554,"height":0.017777778},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Switch account","depth":12,"bounds":{"left":0.89375,"top":0.11,"width":0.061805554,"height":0.017777778},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Lukas Kovalik","depth":14,"bounds":{"left":0.110069446,"top":0.28111112,"width":0.062152777,"height":0.020555556},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"More options","depth":13,"bounds":{"left":0.57256943,"top":0.265,"width":0.033333335,"height":0.053333335},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Turn off microphone","depth":14,"bounds":{"left":0.28645834,"top":0.645,"width":0.03888889,"height":0.053333335},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Turn off camera","depth":14,"bounds":{"left":0.33645833,"top":0.645,"width":0.03888889,"height":0.053333335},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Turn on background blur","depth":13,"bounds":{"left":0.38645834,"top":0.645,"width":0.03888889,"height":0.053333335},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Microphone: LakyLak bose qc35 II","depth":13,"bounds":{"left":0.098958336,"top":0.73833334,"width":0.124305554,"height":0.035555556},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Speaker: System Default Speaker Device","depth":13,"bounds":{"left":0.22881944,"top":0.73833334,"width":0.124305554,"height":0.035555556},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Camera: FaceTime HD Camera","depth":13,"bounds":{"left":0.35868055,"top":0.73833334,"width":0.124305554,"height":0.035555556},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Backgrounds and effects","depth":12,"bounds":{"left":0.48854166,"top":0.73833334,"width":0.124305554,"height":0.035555556},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXHeading","text":"Daily - Platform","depth":12,"bounds":{"left":0.62395835,"top":0.33722222,"width":0.31111112,"height":0.04},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Daily - Platform","depth":15,"bounds":{"left":0.71284723,"top":0.33722222,"width":0.13298611,"height":0.04},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"in 1 minute","depth":13,"bounds":{"left":0.7395833,"top":0.38722223,"width":0.07951389,"height":0.033888888},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Use Gemini to take notes Share notes and transcript","depth":12,"bounds":{"left":0.66770834,"top":0.43944445,"width":0.22326389,"height":0.07111111},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Use Gemini to take notes","depth":13,"bounds":{"left":0.709375,"top":0.4561111,"width":0.1125,"height":0.020555556},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Share notes and transcript","depth":13,"bounds":{"left":0.709375,"top":0.47777778,"width":0.1,"height":0.017222222},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Start","depth":13,"bounds":{"left":0.82743055,"top":0.45277777,"width":0.055208333,"height":0.044444446},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Start","depth":15,"bounds":{"left":0.8440972,"top":0.465,"width":0.021875,"height":0.020555556},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Join now","depth":13,"bounds":{"left":0.6961806,"top":0.5283333,"width":0.16666667,"height":0.062222224},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":true,"is_selected":false},{"role":"AXStaticText","text":"Join now","depth":15,"bounds":{"left":0.7590278,"top":0.54944444,"width":0.040625,"height":0.020555556},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Other ways to join","depth":13,"bounds":{"left":0.71458334,"top":0.62166667,"width":0.12951389,"height":0.044444446},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Gemini is available in Meet as your personal in-meeting assistant. It can analyze conversation via temporary access to meeting captions. Using Ask Gemini won't create a recording or store meeting data. The meeting host can turn it off.","depth":12,"bounds":{"left":0.296875,"top":0.9,"width":0.46770832,"height":0.055},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Learn more","depth":12,"bounds":{"left":0.5486111,"top":0.93666667,"width":0.049652778,"height":0.018333333},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Learn more","depth":13,"bounds":{"left":0.5486111,"top":0.93666667,"width":0.049652778,"height":0.018333333},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Your camera is on. Your microphone is on.","depth":8,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Background is now replaced","depth":8,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"}]...
|
568804048593794615
|
1084019535072452307
|
visual_change
|
hybrid
|
NULL
|
Meet - Daily - Platform
Close tab
New Tab
Open Goo Meet - Daily - Platform
Close tab
New Tab
Open Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
Customize sidebar
Return to home screen
[EMAIL]
Switch account
Switch account
Lukas Kovalik
More options
Turn off microphone
Turn off camera
Turn on background blur
Microphone: LakyLak bose qc35 II
Speaker: System Default Speaker Device
Camera: FaceTime HD Camera
Backgrounds and effects
Daily - Platform
Daily - Platform
in 1 minute
Use Gemini to take notes Share notes and transcript
Use Gemini to take notes
Share notes and transcript
Start
Start
Join now
Join now
Other ways to join
Gemini is available in Meet as your personal in-meeting assistant. It can analyze conversation via temporary access to meeting captions. Using Ask Gemini won't create a recording or store meeting data. The meeting host can turn it off.
Learn more
Learn more
Your camera is on. Your microphone is on.
Background is now replaced
ClaudeFileEditViewWindowHelpDaily - Platform • in 1 m100% C 8• Tue 19 May 9:44:23→Cmeet.google.com/agt-teir-cwt?authuser=lukas.kovalik%40jiminny.comC Meet - Daily - Platform+ New [EMAIL] accountLukas KovalikDaily - Platformin 1 minute*J Use Gemini to take notesShare notes and transcriptStartJoin nowOther ways to joinLakyLak bo...4) System Def...D FaceTime H... •& Backgroun…..Gemini is available in Meet as your personal in-meeting assistant. It can analyze conversation via temporaryaccess to meeting captions. Using Ask Gemini won't create a recording or store meeting data. The meetinghost can turn it off. Learn more...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
55710
|
1934
|
6
|
2026-05-19T06:44:27.372259+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779173067372_m1.jpg...
|
Firefox
|
NULL
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
ClaudeFileEditViewWindowHelp→ Cmeet.google.com/agt ClaudeFileEditViewWindowHelp→ Cmeet.google.com/agt-teir-cwt?authuser=lukas.kovalik%40jiminny.com•1 MeetLukas KovalikDaily - Platform • in 1m100% C• .All-In-Onec, Capture AreaC: Capture Previous Area• Capture Fullscreen• Capture Windowi Scrolling Capture• Self-TimerAa Capture Text (OCR)• Record Screen+85084083Hide Desktop Icons• Open...& Pin to the Screen...D Capture History...About CleanShot...Check for Updates...Settings...QuitTKTOTRatformtв utenotescriptStartNTue 19 May 9:44:[EMAIL] accountOuner ways to joinI LakyLak bos...4 System Defa...• FaceTime HD...g Backgrounds...Gemini is available in Meet as your personal in-meeting assistant. It can analyze conversation via temporaryaccess to meeting captions. Using Ask Gemini won't create a recording or store meeting data. The meetinghost can turn it off. Learn more...
|
NULL
|
-6548729674346417128
|
NULL
|
click
|
ocr
|
NULL
|
ClaudeFileEditViewWindowHelp→ Cmeet.google.com/agt ClaudeFileEditViewWindowHelp→ Cmeet.google.com/agt-teir-cwt?authuser=lukas.kovalik%40jiminny.com•1 MeetLukas KovalikDaily - Platform • in 1m100% C• .All-In-Onec, Capture AreaC: Capture Previous Area• Capture Fullscreen• Capture Windowi Scrolling Capture• Self-TimerAa Capture Text (OCR)• Record Screen+85084083Hide Desktop Icons• Open...& Pin to the Screen...D Capture History...About CleanShot...Check for Updates...Settings...QuitTKTOTRatformtв utenotescriptStartNTue 19 May 9:44:[EMAIL] accountOuner ways to joinI LakyLak bos...4 System Defa...• FaceTime HD...g Backgrounds...Gemini is available in Meet as your personal in-meeting assistant. It can analyze conversation via temporaryaccess to meeting captions. Using Ask Gemini won't create a recording or store meeting data. The meetinghost can turn it off. Learn more...
|
55709
|
NULL
|
NULL
|
NULL
|
|
55711
|
1934
|
7
|
2026-05-19T06:44:35.600685+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779173075600_m1.jpg...
|
Firefox
|
NULL
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
ClaudeFileEditViewWindowHelp→ Cmeet.google.com/agt ClaudeFileEditViewWindowHelp→ Cmeet.google.com/agt-teir-cwt?authuser=lukas.kovalik%40jiminny.com•1 MeetLukas KovalikDaily - Platform • in 1m100% C• .All-In-Onec, Capture AreaC: Capture Previous Area• Capture Fullscreen• Capture Windowi Scrolling Capture• Self-TimerAa Capture Text (OCR)• Record Screen+85084083Hide Desktop Icons• Open...& Pin to the Screen...D Capture History...About CleanShot...Check for Updates...Settings...QuitTKTOTRatformtв utenotescriptStartNTue 19 May 9:44:[EMAIL] accountOuner ways to joinI LakyLak bos...4 System Defa...• FaceTime HD...g Backgrounds...Gemini is available in Meet as your personal in-meeting assistant. It can analyze conversation via temporaryaccess to meeting captions. Using Ask Gemini won't create a recording or store meeting data. The meetinghost can turn it off. Learn more...
|
NULL
|
8219142190238204105
|
NULL
|
click
|
ocr
|
NULL
|
ClaudeFileEditViewWindowHelp→ Cmeet.google.com/agt ClaudeFileEditViewWindowHelp→ Cmeet.google.com/agt-teir-cwt?authuser=lukas.kovalik%40jiminny.com•1 MeetLukas KovalikDaily - Platform • in 1m100% C• .All-In-Onec, Capture AreaC: Capture Previous Area• Capture Fullscreen• Capture Windowi Scrolling Capture• Self-TimerAa Capture Text (OCR)• Record Screen+85084083Hide Desktop Icons• Open...& Pin to the Screen...D Capture History...About CleanShot...Check for Updates...Settings...QuitTKTOTRatformtв utenotescriptStartNTue 19 May 9:44:[EMAIL] accountOuner ways to joinI LakyLak bos...4 System Defa...• FaceTime HD...g Backgrounds...Gemini is available in Meet as your personal in-meeting assistant. It can analyze conversation via temporaryaccess to meeting captions. Using Ask Gemini won't create a recording or store meeting data. The meetinghost can turn it off. Learn more...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
55712
|
1934
|
8
|
2026-05-19T06:44:36.628873+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779173076628_m1.jpg...
|
Firefox
|
Meet - Daily - Platform — Work
|
1
|
meet.google.com/agt-teir-cwt?authuser=lukas.kovali meet.google.com/agt-teir-cwt?authuser=lukas.kovalik%40jiminny.com...
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Meet - Daily - Platform
Close tab
New Tab
Open Goo Meet - Daily - Platform
Close tab
New Tab
Open Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
Customize sidebar
Return to home screen
[EMAIL]
Switch account
Switch account
Lukas Kovalik
More options
Turn off microphone
Turn off camera
Turn on background blur
Microphone: LakyLak bose qc35 II
Speaker: System Default Speaker Device
Camera: FaceTime HD Camera
Backgrounds and effects
Daily - Platform
Daily - Platform
in 1 minute
Use Gemini to take notes Share notes and transcript
Use Gemini to take notes
Share notes and transcript
Start
Start
Join now
Join now
Other ways to join
Gemini is available in Meet as your personal in-meeting assistant. It can analyze conversation via temporary access to meeting captions. Using Ask Gemini won't create a recording or store meeting data. The meeting host can turn it off.
Learn more
Learn more
Your camera is on. Your microphone is on.
Background is now replaced...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Meet - Daily - Platform","depth":4,"bounds":{"left":0.0,"top":0.072222225,"width":0.033680554,"height":0.045555554},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.0013888889,"top":0.072222225,"width":0.010416667,"height":0.016666668},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New Tab","depth":4,"bounds":{"left":0.005902778,"top":0.12,"width":0.022222223,"height":0.035555556},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open Google Gemini (⌃X)","depth":6,"bounds":{"left":0.0,"top":0.7977778,"width":0.033680554,"height":0.043333333},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Tabs from other devices","depth":6,"bounds":{"left":0.0,"top":0.8411111,"width":0.033680554,"height":0.038333334},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"bounds":{"left":0.0,"top":0.8794444,"width":0.033680554,"height":0.03888889},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"bounds":{"left":0.0,"top":0.91833335,"width":0.033680554,"height":0.038333334},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"bounds":{"left":0.0,"top":0.95666665,"width":0.033680554,"height":0.043333333},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Return to home screen","depth":10,"bounds":{"left":0.044791665,"top":0.09,"width":0.072916664,"height":0.044444446},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"lukas.kovalik@jiminny.com","depth":12,"bounds":{"left":0.83923614,"top":0.09166667,"width":0.11631945,"height":0.018333333},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Switch account","depth":11,"bounds":{"left":0.89375,"top":0.11,"width":0.061805554,"height":0.017777778},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Switch account","depth":12,"bounds":{"left":0.89375,"top":0.11,"width":0.061805554,"height":0.017777778},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Lukas Kovalik","depth":14,"bounds":{"left":0.110069446,"top":0.28111112,"width":0.062152777,"height":0.020555556},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"More options","depth":13,"bounds":{"left":0.57256943,"top":0.265,"width":0.033333335,"height":0.053333335},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Turn off microphone","depth":14,"bounds":{"left":0.28645834,"top":0.645,"width":0.03888889,"height":0.053333335},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Turn off camera","depth":14,"bounds":{"left":0.33645833,"top":0.645,"width":0.03888889,"height":0.053333335},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Turn on background blur","depth":13,"bounds":{"left":0.38645834,"top":0.645,"width":0.03888889,"height":0.053333335},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Microphone: LakyLak bose qc35 II","depth":13,"bounds":{"left":0.098958336,"top":0.73833334,"width":0.124305554,"height":0.035555556},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Speaker: System Default Speaker Device","depth":13,"bounds":{"left":0.22881944,"top":0.73833334,"width":0.124305554,"height":0.035555556},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Camera: FaceTime HD Camera","depth":13,"bounds":{"left":0.35868055,"top":0.73833334,"width":0.124305554,"height":0.035555556},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Backgrounds and effects","depth":12,"bounds":{"left":0.48854166,"top":0.73833334,"width":0.124305554,"height":0.035555556},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXHeading","text":"Daily - Platform","depth":12,"bounds":{"left":0.62395835,"top":0.33722222,"width":0.31111112,"height":0.04},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Daily - Platform","depth":15,"bounds":{"left":0.71284723,"top":0.33722222,"width":0.13298611,"height":0.04},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"in 1 minute","depth":13,"bounds":{"left":0.7395833,"top":0.38722223,"width":0.07951389,"height":0.033888888},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Use Gemini to take notes Share notes and transcript","depth":12,"bounds":{"left":0.66770834,"top":0.43944445,"width":0.22326389,"height":0.07111111},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Use Gemini to take notes","depth":13,"bounds":{"left":0.709375,"top":0.4561111,"width":0.1125,"height":0.020555556},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Share notes and transcript","depth":13,"bounds":{"left":0.709375,"top":0.47777778,"width":0.1,"height":0.017222222},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Start","depth":13,"bounds":{"left":0.82743055,"top":0.45277777,"width":0.055208333,"height":0.044444446},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Start","depth":15,"bounds":{"left":0.8440972,"top":0.465,"width":0.021875,"height":0.020555556},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Join now","depth":13,"bounds":{"left":0.6961806,"top":0.5283333,"width":0.16666667,"height":0.062222224},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Join now","depth":15,"bounds":{"left":0.7590278,"top":0.54944444,"width":0.040625,"height":0.020555556},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Other ways to join","depth":13,"bounds":{"left":0.71458334,"top":0.62166667,"width":0.12951389,"height":0.044444446},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Gemini is available in Meet as your personal in-meeting assistant. It can analyze conversation via temporary access to meeting captions. Using Ask Gemini won't create a recording or store meeting data. The meeting host can turn it off.","depth":12,"bounds":{"left":0.296875,"top":0.9,"width":0.46770832,"height":0.055},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Learn more","depth":12,"bounds":{"left":0.5486111,"top":0.93666667,"width":0.049652778,"height":0.018333333},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Learn more","depth":13,"bounds":{"left":0.5486111,"top":0.93666667,"width":0.049652778,"height":0.018333333},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Your camera is on. Your microphone is on.","depth":8,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Background is now replaced","depth":8,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"}]...
|
568804048593794615
|
1084019535072452307
|
click
|
hybrid
|
NULL
|
Meet - Daily - Platform
Close tab
New Tab
Open Goo Meet - Daily - Platform
Close tab
New Tab
Open Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
Customize sidebar
Return to home screen
[EMAIL]
Switch account
Switch account
Lukas Kovalik
More options
Turn off microphone
Turn off camera
Turn on background blur
Microphone: LakyLak bose qc35 II
Speaker: System Default Speaker Device
Camera: FaceTime HD Camera
Backgrounds and effects
Daily - Platform
Daily - Platform
in 1 minute
Use Gemini to take notes Share notes and transcript
Use Gemini to take notes
Share notes and transcript
Start
Start
Join now
Join now
Other ways to join
Gemini is available in Meet as your personal in-meeting assistant. It can analyze conversation via temporary access to meeting captions. Using Ask Gemini won't create a recording or store meeting data. The meeting host can turn it off.
Learn more
Learn more
Your camera is on. Your microphone is on.
Background is now replaced
ClaudeFileEditView→ CWindowHelpDaily - Platform - in 1 mA100% < • Tue 19 May 9:44:36meet.google.com/agt-teir-cwt?authuser=lukas.kovalik%40jiminny.comI [EMAIL] accountLukas KovalikDaily - Platformin 1 minute. Use Gemini to take notesShare notes and transcriptStartJoin nowOther ways to joinI LakyLak bos...4 System Defa...• FaceTime HD...g Backgrounds...Gemini is available in Meet as your personal in-meeting assistant. It can analyze conversation via temporaryaccess to meeting captions. Using Ask Gemini won't create a recording or store meeting data. The meetinghost can turn it off. Learn more...
|
55711
|
NULL
|
NULL
|
NULL
|
|
55713
|
1934
|
9
|
2026-05-19T06:44:39.997122+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779173079997_m1.jpg...
|
CleanShot X
|
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
ClaudeFileEditViewWindowHelp→ CDaily - Platform • ClaudeFileEditViewWindowHelp→ CDaily - Platform • in 1 mA100% 0 8Tue 19 May 9:44:39 •meet.google.com/agt-teir-cwt?authuser=lukas.kovalik%40jiminny.com11 [EMAIL] account+Lukas KovalikDaily - Platformin 1 minute1440x900**• Use Gemini to take notesShare notes and transcriptStartRecord GIFRecord VideoTFTSJoin nowOther ways to join~I LakyLak bos...4 System Defa...FaceTime HD...g Backgrounds...Gemini is available in Meet as your personal in-meeting assistant. It can analyze conversation via temporaryaccess to meeting captions. Using Ask Gemini won't create a recording or store meeting data. The meetinghost can turn it off. Learn more...
|
NULL
|
-1466113783530108891
|
NULL
|
click
|
ocr
|
NULL
|
ClaudeFileEditViewWindowHelp→ CDaily - Platform • ClaudeFileEditViewWindowHelp→ CDaily - Platform • in 1 mA100% 0 8Tue 19 May 9:44:39 •meet.google.com/agt-teir-cwt?authuser=lukas.kovalik%40jiminny.com11 [EMAIL] account+Lukas KovalikDaily - Platformin 1 minute1440x900**• Use Gemini to take notesShare notes and transcriptStartRecord GIFRecord VideoTFTSJoin nowOther ways to join~I LakyLak bos...4 System Defa...FaceTime HD...g Backgrounds...Gemini is available in Meet as your personal in-meeting assistant. It can analyze conversation via temporaryaccess to meeting captions. Using Ask Gemini won't create a recording or store meeting data. The meetinghost can turn it off. Learn more...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
55714
|
1934
|
10
|
2026-05-19T06:44:40.762544+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779173080762_m1.jpg...
|
CleanShot X
|
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
• 0ClaudeFileEdit→F MeetViewWindowHelp‹>0§ Dail • 0ClaudeFileEdit→F MeetViewWindowHelp‹>0§ Daily - Platform • in 1 ml100% (42 Tue 19 May 9:44:40 •meet.google.com/agt-teir-cwt?authuser=[EMAIL] accountLukas KovalikDaily - Platformin 1 minute1356x807• Use Gemini to take notesShare notes and transcriptStartJoin nowGIF)Record GIFRecord VideoTFOther ways to joinI LakyLak bos...4 System Defa...• FaceTime HD...g Backgrounds...Gemini is available in Meet as your personal in-meeting assistant. It can analyze conversation via temporaryaccess to meeting captions. Using Ask Gemini won't create a recording or store meeting data. The meetinghost can turn it off. Learn more...
|
NULL
|
6683419992525080077
|
NULL
|
visual_change
|
ocr
|
NULL
|
• 0ClaudeFileEdit→F MeetViewWindowHelp‹>0§ Dail • 0ClaudeFileEdit→F MeetViewWindowHelp‹>0§ Daily - Platform • in 1 ml100% (42 Tue 19 May 9:44:40 •meet.google.com/agt-teir-cwt?authuser=[EMAIL] accountLukas KovalikDaily - Platformin 1 minute1356x807• Use Gemini to take notesShare notes and transcriptStartJoin nowGIF)Record GIFRecord VideoTFOther ways to joinI LakyLak bos...4 System Defa...• FaceTime HD...g Backgrounds...Gemini is available in Meet as your personal in-meeting assistant. It can analyze conversation via temporaryaccess to meeting captions. Using Ask Gemini won't create a recording or store meeting data. The meetinghost can turn it off. Learn more...
|
55713
|
NULL
|
NULL
|
NULL
|
|
55715
|
1934
|
11
|
2026-05-19T06:44:43.762167+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779173083762_m1.jpg...
|
CleanShot X
|
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
ClaudeFileEditViewWindowHelp‹>0a Daily - Platfo ClaudeFileEditViewWindowHelp‹>0a Daily - Platform • in 1 m100% (42• Tue 19 May 9:44:43 •meet.google.com/agt-teir-cwt?authuser=lukas.kovalik%40jiminny.com=• [EMAIL] accountLukas Kovalik1394(94)833Daily - Platformin 1 minute* Use Gemini to take notesShare notes and transcriptStart*Record GIF• Record Video*TFTSJoin nowOther ways to join~{ LakyLak bos…..4 System Defa...• FaceTime HD...g Backgrounds...Gemini is available in Meet as your personal in-meeting assistant. It can analyze conversation via temporaryaccess to meeting captions. Using Ask Gemini won't create a recording or store meeting data. The meetinghost can turn it off. Learn moreLộ3...
|
NULL
|
3420232318011761418
|
NULL
|
visual_change
|
ocr
|
NULL
|
ClaudeFileEditViewWindowHelp‹>0a Daily - Platfo ClaudeFileEditViewWindowHelp‹>0a Daily - Platform • in 1 m100% (42• Tue 19 May 9:44:43 •meet.google.com/agt-teir-cwt?authuser=lukas.kovalik%40jiminny.com=• [EMAIL] accountLukas Kovalik1394(94)833Daily - Platformin 1 minute* Use Gemini to take notesShare notes and transcriptStart*Record GIF• Record Video*TFTSJoin nowOther ways to join~{ LakyLak bos…..4 System Defa...• FaceTime HD...g Backgrounds...Gemini is available in Meet as your personal in-meeting assistant. It can analyze conversation via temporaryaccess to meeting captions. Using Ask Gemini won't create a recording or store meeting data. The meetinghost can turn it off. Learn moreLộ3...
|
NULL
|
NULL
|
NULL
|
NULL
|