|
55654
|
1931
|
17
|
2026-05-19T06:35:35.964792+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779172535964_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
Copy prompt
You said I’m on page “<tabTitle>JY-20808 low priority indexing queue by Vasil-Jimi</tabTitle>” with “<selection>@@ -5,84 +5,140 @@5namespace Tests\Unit\Component\ES\Processor\DTOs;5namespace Tests\Unit\Component\ES\Processor\DTOs;667use Jiminny\Component\ES\Processor\DTOs\SelectionList;7use Jiminny\Component\ES\Processor\DTOs\SelectionList;8+use Jiminny\Component\ES\QueuePriorityEnum;8use PHPUnit\Framework\Attributes\CoversClass;9use PHPUnit\Framework\Attributes\CoversClass;9use PHPUnit\Framework\TestCase;10use PHPUnit\Framework\TestCase;101111#[CoversClass(SelectionList::class)]12#[CoversClass(SelectionList::class)]12final class SelectionListTest extends TestCase13final class SelectionListTest extends TestCase13{14{14-public function testGetEntityIds(): void15+private const int CHUNK_SIZE = 100;16+17+public function testAddEntityListAndGetAllIds(): void18+ {19+$selectionList = new SelectionList();20+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);21+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);22+23+$this->assertSame([1, 2, 3, 4], $selectionList->getAllIds());24+ }25+26+public function testAddEntityListMergesMultipleCallsForSamePriority(): void27+ {28+$selectionList = new SelectionList();29+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);30+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [3, 4]);31+32+$this->assertSame([1, 2, 3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));33+ }34+35+public function testGetEntityListItemsByGroup(): void36+ {37+$selectionList = new SelectionList();38+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);39+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);40+$selectionList->addEntityList(QueuePriorityEnum::LOW, [5, 6]);41+42+$this->assertSame([1, 2], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));43+$this->assertSame([3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::NORMAL));44+$this->assertSame([5, 6], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::LOW));45+ }46+47+public function testGetEntityListItemsByGroupReturnsEmptyArrayForUnknownGroup(): void15 {48 {16-$priority = ['p1', 'p2'];49+$selectionList = new SelectionList();17-$normal = ['n1', 'n2'];50+18-$selectionList = new SelectionList($priority, $normal);51+$this->assertSame([], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));52+ }195320-$this->assertSame($priority, $selectionList->getHighPriorityEntityIds());54+public function testGetEntityListGroups(): void21-$this->assertSame($normal, $selectionList->getNormalPriorityEntityId());55+ {56+$selectionList = new SelectionList();57+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);58+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2]);225923-$this->assertSame(['p1', 'p2', 'n1', 'n2'], $selectionList->getAllIds());60+$this->assertSame(['high', 'normal'], $selectionList->getEntityListGroups());24 }61 }256226public function testCountReturnsTotalCount(): void63public function testCountReturnsTotalCount(): void27 {64 {28-$selectionList = new SelectionList(['p1'], ['n1', 'n2']);65+$selectionList = new SelectionList();66+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);67+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2, 3]);68+29$this->assertSame(3, $selectionList->count());69$this->assertSame(3, $selectionList->count());30 }70 }317132-public function testIsEmptyReturnsTrueWhenBothListsAreEmpty(): void72+public function testIsEmptyReturnsTrueWhenNoEntitiesAdded(): void33 {73 {34-$selectionList = new SelectionList([], []);74+$selectionList = new SelectionList();75+35$this->assertTrue($selectionList->isEmpty());76$this->assertTrue($selectionList->isEmpty());36 }77 }377838-public function testIsEmptyReturnsFalseWhenAnyListIsNotEmpty(): void79+public function testIsEmptyReturnsFalseWhenEntitiesAdded(): void39 {80 {40-$selectionList = new SelectionList(['p1'], []);81+$selectionList = new SelectionList();41-$this->assertFalse($selectionList->isEmpty());82+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);428343-$selectionList2 = new SelectionList([], ['n1']);84+$this->assertFalse($selectionList->isEmpty());44-$this->assertFalse($selectionList2->isEmpty());45 }85 }468647-public function testIsStaleChunkSelected(): void87+public function testMarkStaleAndIsStaleChunkSelected(): void48 {88 {49-$selectionList = new SelectionList([], [], true);89+$selectionList = new SelectionList();50-$this->assertTrue($selectionList->isStaleChunkSelected());90+91+$this->assertFalse($selectionList->isStaleChunkSelected());92+93+$selectionList->markStale();519452-$selectionList2 = new SelectionList([], [], false);95+$this->assertTrue($selectionList->isStaleChunkSelected());53-$this->assertFalse($selectionList2->isStaleChunkSelected());54 }96 }559756public function testIsFullChunk(): void98public function testIsFullChunk(): void57 {99 {58-$chunkSize = 200;100+$selectionList = new SelectionList();59-101+$selectionList->setChunkSize(self::CHUNK_SIZE);60-$fullList = range(1, $chunkSize);102+61-$selectionList = new SelectionList(103+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, self::CHUNK_SIZE));62- priorityEntityIdList: $fullList,104+63- normalEntityIdList: [],105+$this->assertTrue($selectionList->isFullChunk());64- chunkSize: $chunkSize,106+ }65- );107+108+public function testIsNotFullChunkWhenBelowChunkSize(): void109+ {110+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);111+112+$selectionList = new SelectionList();113+$selectionList->setChunkSize(self::CHUNK_SIZE);114+115+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range(1, $halfRange));116+117+$this->assertFalse($selectionList->isFullChunk());118+ }119+120+public function testIsFullChunkAcrossMultiplePriorityGroups(): void121+ {122+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);123+124+$selectionList = new SelectionList();125+$selectionList->setChunkSize(self::CHUNK_SIZE);126+127+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, $halfRange));128+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range($halfRange + 1, self::CHUNK_SIZE));129+130+$this->assertTrue($selectionList->isFullChunk());131+ }132+133+public function testSetChunkSizeAffectsIsFullChunk(): void134+ {135+$selectionList = new SelectionList();136+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [1, 2, 3]);137+138+$selectionList->setChunkSize(3);66$this->assertTrue($selectionList->isFullChunk());139$this->assertTrue($selectionList->isFullChunk());6714068-$halfRange = (int) ceil($chunkSize / 2);141+$selectionList->setChunkSize(50);69-142+$this->assertFalse($selectionList->isFullChunk());70-$notFullList = range(1, $halfRange);71-$selectionList2 = new SelectionList(72- priorityEntityIdList: $notFullList,73- normalEntityIdList: [],74- chunkSize: $chunkSize,75- );76-$this->assertFalse($selectionList2->isFullChunk());77-78-$priorityRange = range(1, $halfRange);79-$normalRange = range($halfRange + 1, $chunkSize);80-81-$selectionList3 = new SelectionList(82- priorityEntityIdList: $priorityRange,83- normalEntityIdList: $normalRange,84- chunkSize: $chunkSize,85- );86-$this->assertTrue($selectionList3->isFullChunk());87 }143 }88}144}</selection>” selected. Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
You said
I’m on page “<tabTitle>JY-20808 low priority indexing queue by Vasil-Jimi</tabTitle>” with “<selection>@@ -5,84 +5,140 @@5namespace Tests\Unit\Component\ES\Processor\DTOs;5namespace Tests\Unit\Component\ES\Processor\DTOs;667use Jiminny\Component\ES\Processor\DTOs\SelectionList;7use Jiminny\Component\ES\Processor\DTOs\SelectionList;8+use Jiminny\Component\ES\QueuePriorityEnum;8use PHPUnit\Framework\Attributes\CoversClass;9use PHPUnit\Framework\Attributes\CoversClass;9use PHPUnit\Framework\TestCase;10use PHPUnit\Framework\TestCase;101111#[CoversClass(SelectionList::class)]12#[CoversClass(SelectionList::class)]12final class SelectionListTest extends TestCase13final class SelectionListTest extends TestCase13{14{14-public function testGetEntityIds(): void15+private const int CHUNK_SIZE = 100;16+17+public function testAddEntityListAndGetAllIds(): void18+ {19+$selectionList = new SelectionList();20+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);21+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);22+23+$this->assertSame([1, 2, 3, 4], $selectionList->getAllIds());24+ }25+26+public function testAddEntityListMergesMultipleCallsForSamePriority(): void27+ {28+$selectionList = new SelectionList();29+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);30+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [3, 4]);31+32+$this->assertSame([1, 2, 3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));33+ }34+35+public function testGetEntityListItemsByGroup(): void36+ {37+$selectionList = new SelectionList();38+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);39+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);40+$selectionList->addEntityList(QueuePriorityEnum::LOW, [5, 6]);41+42+$this->assertSame([1, 2], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));43+$this->assertSame([3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::NORMAL));44+$this->assertSame([5, 6], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::LOW));45+ }46+47+public function testGetEntityListItemsByGroupReturnsEmptyArrayForUnknownGroup(): void15 {48 {16-$priority = ['p1', 'p2'];49+$selectionList = new SelectionList();17-$normal = ['n1', 'n2'];50+18-$selectionList = new SelectionList($priority, $normal);51+$this->assertSame([], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));52+ }195320-$this->assertSame($priority, $selectionList->getHighPriorityEntityIds());54+public function testGetEntityListGroups(): void21-$this->assertSame($normal, $selectionList->getNormalPriorityEntityId());55+ {56+$selectionList = new SelectionList();57+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);58+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2]);225923-$this->assertSame(['p1', 'p2', 'n1', 'n2'], $selectionList->getAllIds());60+$this->assertSame(['high', 'normal'], $selectionList->getEntityListGroups());24 }61 }256226public function testCountReturnsTotalCount(): void63public function testCountReturnsTotalCount(): void27 {64 {28-$selectionList = new SelectionList(['p1'], ['n1', 'n2']);65+$selectionList = new SelectionList();66+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);67+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2, 3]);68+29$this->assertSame(3, $selectionList->count());69$this->assertSame(3, $selectionList->count());30 }70 }317132-public function testIsEmptyReturnsTrueWhenBothListsAreEmpty(): void72+public function testIsEmptyReturnsTrueWhenNoEntitiesAdded(): void33 {73 {34-$selectionList = new SelectionList([], []);74+$selectionList = new SelectionList();75+35$this->assertTrue($selectionList->isEmpty());76$this->assertTrue($selectionList->isEmpty());36 }77 }377838-public function testIsEmptyReturnsFalseWhenAnyListIsNotEmpty(): void79+public function testIsEmptyReturnsFalseWhenEntitiesAdded(): void39 {80 {40-$selectionList = new SelectionList(['p1'], []);81+$selectionList = new SelectionList();41-$this->assertFalse($selectionList->isEmpty());82+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);428343-$selectionList2 = new SelectionList([], ['n1']);84+$this->assertFalse($selectionList->isEmpty());44-$this->assertFalse($selectionList2->isEmpty());45 }85 }468647-public function testIsStaleChunkSelected(): void87+public function testMarkStaleAndIsStaleChunkSelected(): void48 {88 {49-$selectionList = new SelectionList([], [], true);89+$selectionList = new SelectionList();50-$this->assertTrue($selectionList->isStaleChunkSelected());90+91+$this->assertFalse($selectionList->isStaleChunkSelected());92+93+$selectionList->markStale();519452-$selectionList2 = new SelectionList([], [], false);95+$this->assertTrue($selectionList->isStaleChunkSelected());53-$this->assertFalse($selectionList2->isStaleChunkSelected());54 }96 }559756public function testIsFullChunk(): void98public function testIsFullChunk(): void57 {99 {58-$chunkSize = 200;100+$selectionList = new SelectionList();59-101+$selectionList->setChunkSize(self::CHUNK_SIZE);60-$fullList = range(1, $chunkSize);102+61-$selectionList = new SelectionList(103+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, self::CHUNK_SIZE));62- priorityEntityIdList: $fullList,104+63- normalEntityIdList: [],105+$this->assertTrue($selectionList->isFullChunk());64- chunkSize: $chunkSize,106+ }65- );107+108+public function testIsNotFullChunkWhenBelowChunkSize(): void109+ {110+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);111+112+$selectionList = new SelectionList();113+$selectionList->setChunkSize(self::CHUNK_SIZE);114+115+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range(1, $halfRange));116+117+$this->assertFalse($selectionList->isFullChunk());118+ }119+120+public function testIsFullChunkAcrossMultiplePriorityGroups(): void121+ {122+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);123+124+$selectionList = new SelectionList();125+$selectionList->setChunkSize(self::CHUNK_SIZE);126+127+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, $halfRange));128+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range($halfRange + 1, self::CHUNK_SIZE));129+130+$this->assertTrue($selectionList->isFullChunk());131+ }132+133+public function testSetChunkSizeAffectsIsFullChunk(): void134+ {135+$selectionList = new SelectionList();136+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [1, 2, 3]);137+138+$selectionList->setChunkSize(3);66$this->assertTrue($selectionList->isFullChunk());139$this->assertTrue($selectionList->isFullChunk());6714068-$halfRange = (int) ceil($chunkSize / 2);141+$selectionList->setChunkSize(50);69-142+$this->assertFalse($selectionList->isFullChunk());70-$notFullList = range(1, $halfRange);71-$selectionList2 = new SelectionList(72- priorityEntityIdList: $notFullList,73- normalEntityIdList: [],74- chunkSize: $chunkSize,75- );76-$this->assertFalse($selectionList2->isFullChunk());77-78-$priorityRange = range(1, $halfRange);79-$normalRange = range($halfRange + 1, $chunkSize);80-81-$selectionList3 = new SelectionList(82- priorityEntityIdList: $priorityRange,83- normalEntityIdList: $normalRange,84- chunkSize: $chunkSize,85- );86-$this->assertTrue($selectionList3->isFullChunk());87 }143 }88}144}</selection>” selected.
Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
Expand
Listen
Gemini said
Gemini said
Here is a precise and concise summary of the code selection, which refactors
SelectionListTest
to accommodate a shift from fixed high/normal priority properties to a more dynamic, enum-driven priority group architecture.
Refactored Priority Handling
Refactored Priority Handling
Dynamic Priority Groups:
Replaces fixed high/normal array parameters with the
QueuePriorityEnum
(
HIGH
,
NORMAL
,
LOW
), allowing entity lists to be managed dynamically by group types.
Merged Registrations:
Validates that multiple
addEntityList()
calls targeting the same priority level properly merge their data instead of overwriting it.
Group Querying:
Tests new methods
getEntityListItemsByGroup()
and
getEntityListGroups()
to retrieve group-specific IDs or an array of active group names (e.g.,
['high', 'normal']
).
Updated State and Count Validations
Updated State and Count Validations
Instantiation:
Tests now instantiate
SelectionList
without initial constructor arguments, using setters and action methods instead.
Empty States:
Updates assertions (
isEmpty()
) to verify state based on whether any entities have been dynamically added, rather than checking pre-defined constructor arrays.
Stale Flags:
Changes from passing a
stale
boolean via the constructor to explicitly triggering a mutable
$selectionList->markStale()
method.
Chunk Capacity Behavior
Chunk Capacity Behavior
Flexible Chunk Sizes:
Introduces a
setChunkSize()
method, replacing the constructor-configured chunk boundary.
Capacity Assertions:
Retains and updates the logic for
isFullChunk()
, ensuring it accurately evaluates capacity when elements span multiple dynamic priority groups or when the chunk limit is altered mid-lifecycle.
Good response
Bad response
Share & export
Copy
Show more options
Copy prompt
You said Are there any issues or potential bolltenecks
You said
Are there any issues or potential bolltenecks
Listen
Show thinking
Gemini said
Gemini said
Based on the test diff you provided, we can infer a few potential issues and architectural bottlenecks in the underlying
SelectionList
implementation. While the tests are well-structured, the behavior they describe hints at a few areas you might want to keep an eye on, particularly for an Elasticsearch (ES) processor queue.
Here are the potential issues and bottlenecks to consider:
1. Array Merging Overhead (Performance)
1. Array Merging Overhead (Performance)
The
testAddEntityListMergesMultipleCallsForSamePriority
test shows that calling
addEntityList()
multiple times for the same priority group merges the arrays.
The Bottleneck:
If the underlying implementation uses
array_merge()
inside a loop to append these IDs, it creates a new array in memory every time it's called. If you are processing thousands of entities and appending them in small batches, this can lead to memory bloat and CPU degradation due to constant array reallocation.
Mitigation:
Ensure the implementation handles batch appends efficiently (e.g., using the spread operator
[...$existing, ...$new]
or appending via references) or groups the arrays before doing a single merge.
2. Lack of Uniqueness/Deduplication (Logic)
2. Lack of Uniqueness/Deduplication (Logic)
None of the tests explicitly verify what happens if duplicate IDs are added. For example, if you call
addEntityList(QueuePriorityEnum::HIGH, [1, 2])
and then
addEntityList(QueuePriorityEnum::HIGH, [2, 3])
.
The Issue:
Does the getter return
[1, 2, 2, 3]
or
[1, 2, 3]
? If duplicates are not filtered out, your ES processor might end up indexing the same entity multiple times in a single chunk, which wastes I/O and processor cycles.
Mitigation:
The underlying class should ideally enforce uniqueness (e.g., using
array_unique()
before resolving the chunk, or using ID keys as associative array keys to naturally prevent duplicates).
3. Memory Consumption with Large Chunks (Scalability)
3. Memory Consumption with Large Chunks (Scalability)
The tests introduce
setChunkSize()
. If this chunk size is configured to be very large (e.g., tens of thousands of IDs to bulk-send to Elasticsearch).
The Bottleneck:
Holding massive arrays of IDs in memory across different priority groups can quickly hit PHP memory limits, especially if this
SelectionList
object is kept alive during a long-running daemon or cron job.
Mitigation:
Monitor memory usage if
CHUNK_SIZE
grows, and ensure the
SelectionList
object is properly destroyed (or garbage collected) after the chunk is processed to free up memory.
4. Type Juggling
4. Type Juggling
In the original code, string IDs were used (
['p1', 'p2']
). In the refactored tests, integer IDs are used (
[1, 2]
).
The Issue:
If your system handles UUIDs (strings) vs. relational DB auto-increments (integers), make sure the underlying implementation uses strict comparisons (
===
) where necessary, especially if deduplicating arrays, to prevent PHP from juggling
'1'
and
1
improperly.
Would you like me to draft a quick test case to check how the class currently handles duplicate IDs, or is deduplication intentionally handled further down your pipeline?
Good response
Bad response
Share & export
Copy
Show more options
Copy prompt
Edit
You said what about non test files
You said
what about non test files
Listen
Show thinking
Gemini said
Gemini said
Since we don't have the actual
SelectionList.php
file, we have to reverse-engineer its implementation based on the test behaviors. Moving from a constructor-based, fixed-property model to a dynamic, mutable model introduces several potential pitfalls in the implementation file itself.
Here are the specific bottlenecks and issues to watch out for in the
SelectionList.php
source code:
1. The count() Method Implementation (Performance Trap)
1. The
count()
Method Implementation (Performance Trap)
The Risk:
If
count()
is implemented by calling
$this->getAllIds()
and counting the resulting merged array (e.g.,
return count($this->getAllIds());
), it will be highly inefficient. It would allocate a brand-new array in memory just to determine its length.
The Fix:
count()
should mathematically sum the sizes of the underlying group arrays without merging them:
return array_sum(array_map('count', $this->entityLists));
2. Loss of Immutability (State Management)
2. Loss of Immutability (State Management)
The Risk:
The original code passed all data via the constructor, implying the DTO (Data Transfer Object) was immutable once created. The refactored version introduces mutability (
addEntityList()
,
setChunkSize()
,
markStale()
). DTOs are typically passed between architectural layers; if one layer modifies the chunk size or adds entities while another is processing it, it can cause unpredictable side effects or race conditions in your queue processor.
The Fix:
Ensure that this object is not shared across asynchronous contexts, or consider returning cloned instances when mutating state if strict immutability is required.
3. Enum Array Key Violations (PHP Quirks)
3. Enum Array Key Violations (PHP Quirks)
The Risk:
The tests show
QueuePriorityEnum::HIGH
being passed to methods. If the underlying code attempts to use this Enum directly as an array key (e.g.,
$this->lists[$priority] = $ids;
), PHP will throw an error because objects (including Enums) cannot be used as standard array keys.
The Fix:
The implementation must map the Enum to its underlying scalar value (e.g.,
$this->lists[$priority->value]
) or use PHP's
WeakMap
or
SplObjectStorage
, though standard arrays using
$priority->value
are much faster for simple lists.
4. Uninitialized State Defaults (Logic Errors)
4. Uninitialized State Defaults (Logic Errors)
The Risk:
The tests instantiate
new SelectionList()
without arguments, then later call
$selectionList->setChunkSize(100)
. If
isFullChunk()
is called
before
setChunkSize()
is invoked, what happens?
The Fix:
Ensure
SelectionList
has a sensible default for chunk size (e.g.,
private int $chunkSize = 0;
or a system default) to prevent uninitialized property errors or division-by-zero scenarios if your logic ever relies on chunk math.
5. getAllIds() Repeated Execution (CPU Overhead)
5.
getAllIds()
Repeated Execution (CPU Overhead)
The Risk:
If
getAllIds()
dynamically merges arrays (
array_merge(...$this->lists)
) every time it is invoked, and your ES processor calls this method inside a loop, it will spike CPU usage.
The Fix:
If the list is read frequently, the implementation should either cache the merged result and invalidate that cache when
addEntityList()
is called, or the caller should assign the result to a local variable before iterating.
Would you like me to draft an optimal, memory-efficient skeleton for the
SelectionList.php
implementation that avoids these specific pitfalls?
Good response...
|
[{"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":"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 I’m on page “<tabTitle>JY-20808 low priority indexing queue by Vasil-Jimi</tabTitle>” with “<selection>@@ -5,84 +5,140 @@5namespace Tests\\Unit\\Component\\ES\\Processor\\DTOs;5namespace Tests\\Unit\\Component\\ES\\Processor\\DTOs;667use Jiminny\\Component\\ES\\Processor\\DTOs\\SelectionList;7use Jiminny\\Component\\ES\\Processor\\DTOs\\SelectionList;8+use Jiminny\\Component\\ES\\QueuePriorityEnum;8use PHPUnit\\Framework\\Attributes\\CoversClass;9use PHPUnit\\Framework\\Attributes\\CoversClass;9use PHPUnit\\Framework\\TestCase;10use PHPUnit\\Framework\\TestCase;101111#[CoversClass(SelectionList::class)]12#[CoversClass(SelectionList::class)]12final class SelectionListTest extends TestCase13final class SelectionListTest extends TestCase13{14{14-public function testGetEntityIds(): void15+private const int CHUNK_SIZE = 100;16+17+public function testAddEntityListAndGetAllIds(): void18+ {19+$selectionList = new SelectionList();20+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);21+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);22+23+$this->assertSame([1, 2, 3, 4], $selectionList->getAllIds());24+ }25+26+public function testAddEntityListMergesMultipleCallsForSamePriority(): void27+ {28+$selectionList = new SelectionList();29+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);30+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [3, 4]);31+32+$this->assertSame([1, 2, 3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));33+ }34+35+public function testGetEntityListItemsByGroup(): void36+ {37+$selectionList = new SelectionList();38+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);39+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);40+$selectionList->addEntityList(QueuePriorityEnum::LOW, [5, 6]);41+42+$this->assertSame([1, 2], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));43+$this->assertSame([3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::NORMAL));44+$this->assertSame([5, 6], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::LOW));45+ }46+47+public function testGetEntityListItemsByGroupReturnsEmptyArrayForUnknownGroup(): void15 {48 {16-$priority = ['p1', 'p2'];49+$selectionList = new SelectionList();17-$normal = ['n1', 'n2'];50+18-$selectionList = new SelectionList($priority, $normal);51+$this->assertSame([], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));52+ }195320-$this->assertSame($priority, $selectionList->getHighPriorityEntityIds());54+public function testGetEntityListGroups(): void21-$this->assertSame($normal, $selectionList->getNormalPriorityEntityId());55+ {56+$selectionList = new SelectionList();57+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);58+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2]);225923-$this->assertSame(['p1', 'p2', 'n1', 'n2'], $selectionList->getAllIds());60+$this->assertSame(['high', 'normal'], $selectionList->getEntityListGroups());24 }61 }256226public function testCountReturnsTotalCount(): void63public function testCountReturnsTotalCount(): void27 {64 {28-$selectionList = new SelectionList(['p1'], ['n1', 'n2']);65+$selectionList = new SelectionList();66+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);67+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2, 3]);68+29$this->assertSame(3, $selectionList->count());69$this->assertSame(3, $selectionList->count());30 }70 }317132-public function testIsEmptyReturnsTrueWhenBothListsAreEmpty(): void72+public function testIsEmptyReturnsTrueWhenNoEntitiesAdded(): void33 {73 {34-$selectionList = new SelectionList([], []);74+$selectionList = new SelectionList();75+35$this->assertTrue($selectionList->isEmpty());76$this->assertTrue($selectionList->isEmpty());36 }77 }377838-public function testIsEmptyReturnsFalseWhenAnyListIsNotEmpty(): void79+public function testIsEmptyReturnsFalseWhenEntitiesAdded(): void39 {80 {40-$selectionList = new SelectionList(['p1'], []);81+$selectionList = new SelectionList();41-$this->assertFalse($selectionList->isEmpty());82+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);428343-$selectionList2 = new SelectionList([], ['n1']);84+$this->assertFalse($selectionList->isEmpty());44-$this->assertFalse($selectionList2->isEmpty());45 }85 }468647-public function testIsStaleChunkSelected(): void87+public function testMarkStaleAndIsStaleChunkSelected(): void48 {88 {49-$selectionList = new SelectionList([], [], true);89+$selectionList = new SelectionList();50-$this->assertTrue($selectionList->isStaleChunkSelected());90+91+$this->assertFalse($selectionList->isStaleChunkSelected());92+93+$selectionList->markStale();519452-$selectionList2 = new SelectionList([], [], false);95+$this->assertTrue($selectionList->isStaleChunkSelected());53-$this->assertFalse($selectionList2->isStaleChunkSelected());54 }96 }559756public function testIsFullChunk(): void98public function testIsFullChunk(): void57 {99 {58-$chunkSize = 200;100+$selectionList = new SelectionList();59-101+$selectionList->setChunkSize(self::CHUNK_SIZE);60-$fullList = range(1, $chunkSize);102+61-$selectionList = new SelectionList(103+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, self::CHUNK_SIZE));62- priorityEntityIdList: $fullList,104+63- normalEntityIdList: [],105+$this->assertTrue($selectionList->isFullChunk());64- chunkSize: $chunkSize,106+ }65- );107+108+public function testIsNotFullChunkWhenBelowChunkSize(): void109+ {110+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);111+112+$selectionList = new SelectionList();113+$selectionList->setChunkSize(self::CHUNK_SIZE);114+115+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range(1, $halfRange));116+117+$this->assertFalse($selectionList->isFullChunk());118+ }119+120+public function testIsFullChunkAcrossMultiplePriorityGroups(): void121+ {122+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);123+124+$selectionList = new SelectionList();125+$selectionList->setChunkSize(self::CHUNK_SIZE);126+127+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, $halfRange));128+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range($halfRange + 1, self::CHUNK_SIZE));129+130+$this->assertTrue($selectionList->isFullChunk());131+ }132+133+public function testSetChunkSizeAffectsIsFullChunk(): void134+ {135+$selectionList = new SelectionList();136+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [1, 2, 3]);137+138+$selectionList->setChunkSize(3);66$this->assertTrue($selectionList->isFullChunk());139$this->assertTrue($selectionList->isFullChunk());6714068-$halfRange = (int) ceil($chunkSize / 2);141+$selectionList->setChunkSize(50);69-142+$this->assertFalse($selectionList->isFullChunk());70-$notFullList = range(1, $halfRange);71-$selectionList2 = new SelectionList(72- priorityEntityIdList: $notFullList,73- normalEntityIdList: [],74- chunkSize: $chunkSize,75- );76-$this->assertFalse($selectionList2->isFullChunk());77-78-$priorityRange = range(1, $halfRange);79-$normalRange = range($halfRange + 1, $chunkSize);80-81-$selectionList3 = new SelectionList(82- priorityEntityIdList: $priorityRange,83- normalEntityIdList: $normalRange,84- chunkSize: $chunkSize,85- );86-$this->assertTrue($selectionList3->isFullChunk());87 }143 }88}144}</selection>” selected. Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.","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":"I’m on page “<tabTitle>JY-20808 low priority indexing queue by Vasil-Jimi</tabTitle>” with “<selection>@@ -5,84 +5,140 @@5namespace Tests\\Unit\\Component\\ES\\Processor\\DTOs;5namespace Tests\\Unit\\Component\\ES\\Processor\\DTOs;667use Jiminny\\Component\\ES\\Processor\\DTOs\\SelectionList;7use Jiminny\\Component\\ES\\Processor\\DTOs\\SelectionList;8+use Jiminny\\Component\\ES\\QueuePriorityEnum;8use PHPUnit\\Framework\\Attributes\\CoversClass;9use PHPUnit\\Framework\\Attributes\\CoversClass;9use PHPUnit\\Framework\\TestCase;10use PHPUnit\\Framework\\TestCase;101111#[CoversClass(SelectionList::class)]12#[CoversClass(SelectionList::class)]12final class SelectionListTest extends TestCase13final class SelectionListTest extends TestCase13{14{14-public function testGetEntityIds(): void15+private const int CHUNK_SIZE = 100;16+17+public function testAddEntityListAndGetAllIds(): void18+ {19+$selectionList = new SelectionList();20+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);21+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);22+23+$this->assertSame([1, 2, 3, 4], $selectionList->getAllIds());24+ }25+26+public function testAddEntityListMergesMultipleCallsForSamePriority(): void27+ {28+$selectionList = new SelectionList();29+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);30+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [3, 4]);31+32+$this->assertSame([1, 2, 3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));33+ }34+35+public function testGetEntityListItemsByGroup(): void36+ {37+$selectionList = new SelectionList();38+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);39+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);40+$selectionList->addEntityList(QueuePriorityEnum::LOW, [5, 6]);41+42+$this->assertSame([1, 2], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));43+$this->assertSame([3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::NORMAL));44+$this->assertSame([5, 6], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::LOW));45+ }46+47+public function testGetEntityListItemsByGroupReturnsEmptyArrayForUnknownGroup(): void15 {48 {16-$priority = ['p1', 'p2'];49+$selectionList = new SelectionList();17-$normal = ['n1', 'n2'];50+18-$selectionList = new SelectionList($priority, $normal);51+$this->assertSame([], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));52+ }195320-$this->assertSame($priority, $selectionList->getHighPriorityEntityIds());54+public function testGetEntityListGroups(): void21-$this->assertSame($normal, $selectionList->getNormalPriorityEntityId());55+ {56+$selectionList = new SelectionList();57+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);58+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2]);225923-$this->assertSame(['p1', 'p2', 'n1', 'n2'], $selectionList->getAllIds());60+$this->assertSame(['high', 'normal'], $selectionList->getEntityListGroups());24 }61 }256226public function testCountReturnsTotalCount(): void63public function testCountReturnsTotalCount(): void27 {64 {28-$selectionList = new SelectionList(['p1'], ['n1', 'n2']);65+$selectionList = new SelectionList();66+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);67+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2, 3]);68+29$this->assertSame(3, $selectionList->count());69$this->assertSame(3, $selectionList->count());30 }70 }317132-public function testIsEmptyReturnsTrueWhenBothListsAreEmpty(): void72+public function testIsEmptyReturnsTrueWhenNoEntitiesAdded(): void33 {73 {34-$selectionList = new SelectionList([], []);74+$selectionList = new SelectionList();75+35$this->assertTrue($selectionList->isEmpty());76$this->assertTrue($selectionList->isEmpty());36 }77 }377838-public function testIsEmptyReturnsFalseWhenAnyListIsNotEmpty(): void79+public function testIsEmptyReturnsFalseWhenEntitiesAdded(): void39 {80 {40-$selectionList = new SelectionList(['p1'], []);81+$selectionList = new SelectionList();41-$this->assertFalse($selectionList->isEmpty());82+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);428343-$selectionList2 = new SelectionList([], ['n1']);84+$this->assertFalse($selectionList->isEmpty());44-$this->assertFalse($selectionList2->isEmpty());45 }85 }468647-public function testIsStaleChunkSelected(): void87+public function testMarkStaleAndIsStaleChunkSelected(): void48 {88 {49-$selectionList = new SelectionList([], [], true);89+$selectionList = new SelectionList();50-$this->assertTrue($selectionList->isStaleChunkSelected());90+91+$this->assertFalse($selectionList->isStaleChunkSelected());92+93+$selectionList->markStale();519452-$selectionList2 = new SelectionList([], [], false);95+$this->assertTrue($selectionList->isStaleChunkSelected());53-$this->assertFalse($selectionList2->isStaleChunkSelected());54 }96 }559756public function testIsFullChunk(): void98public function testIsFullChunk(): void57 {99 {58-$chunkSize = 200;100+$selectionList = new SelectionList();59-101+$selectionList->setChunkSize(self::CHUNK_SIZE);60-$fullList = range(1, $chunkSize);102+61-$selectionList = new SelectionList(103+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, self::CHUNK_SIZE));62- priorityEntityIdList: $fullList,104+63- normalEntityIdList: [],105+$this->assertTrue($selectionList->isFullChunk());64- chunkSize: $chunkSize,106+ }65- );107+108+public function testIsNotFullChunkWhenBelowChunkSize(): void109+ {110+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);111+112+$selectionList = new SelectionList();113+$selectionList->setChunkSize(self::CHUNK_SIZE);114+115+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range(1, $halfRange));116+117+$this->assertFalse($selectionList->isFullChunk());118+ }119+120+public function testIsFullChunkAcrossMultiplePriorityGroups(): void121+ {122+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);123+124+$selectionList = new SelectionList();125+$selectionList->setChunkSize(self::CHUNK_SIZE);126+127+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, $halfRange));128+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range($halfRange + 1, self::CHUNK_SIZE));129+130+$this->assertTrue($selectionList->isFullChunk());131+ }132+133+public function testSetChunkSizeAffectsIsFullChunk(): void134+ {135+$selectionList = new SelectionList();136+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [1, 2, 3]);137+138+$selectionList->setChunkSize(3);66$this->assertTrue($selectionList->isFullChunk());139$this->assertTrue($selectionList->isFullChunk());6714068-$halfRange = (int) ceil($chunkSize / 2);141+$selectionList->setChunkSize(50);69-142+$this->assertFalse($selectionList->isFullChunk());70-$notFullList = range(1, $halfRange);71-$selectionList2 = new SelectionList(72- priorityEntityIdList: $notFullList,73- normalEntityIdList: [],74- chunkSize: $chunkSize,75- );76-$this->assertFalse($selectionList2->isFullChunk());77-78-$priorityRange = range(1, $halfRange);79-$normalRange = range($halfRange + 1, $chunkSize);80-81-$selectionList3 = new SelectionList(82- priorityEntityIdList: $priorityRange,83- normalEntityIdList: $normalRange,84- chunkSize: $chunkSize,85- );86-$this->assertTrue($selectionList3->isFullChunk());87 }143 }88}144}</selection>” selected.","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Expand","depth":21,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"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":"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":"Here is a precise and concise summary of the code selection, which refactors","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SelectionListTest","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"to accommodate a shift from fixed high/normal priority properties to a more dynamic, enum-driven priority group architecture.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Refactored Priority Handling","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Refactored Priority Handling","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Dynamic Priority Groups:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Replaces fixed high/normal array parameters with the","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"QueuePriorityEnum","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"HIGH","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"NORMAL","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"LOW","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"), allowing entity lists to be managed dynamically by group types.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Merged Registrations:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Validates that multiple","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"addEntityList()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"calls targeting the same priority level properly merge their data instead of overwriting it.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Group Querying:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Tests new methods","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"getEntityListItemsByGroup()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"and","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"getEntityListGroups()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"to retrieve group-specific IDs or an array of active group names (e.g.,","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"['high', 'normal']","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":").","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Updated State and Count Validations","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Updated State and Count Validations","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Instantiation:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Tests now instantiate","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SelectionList","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"without initial constructor arguments, using setters and action methods instead.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Empty States:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Updates assertions (","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"isEmpty()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":") to verify state based on whether any entities have been dynamically added, rather than checking pre-defined constructor arrays.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Stale Flags:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Changes from passing a","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"stale","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"boolean via the constructor to explicitly triggering a mutable","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$selectionList->markStale()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"method.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Chunk Capacity Behavior","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Chunk Capacity Behavior","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Flexible Chunk Sizes:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Introduces a","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"setChunkSize()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"method, replacing the constructor-configured chunk boundary.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Capacity Assertions:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Retains and updates the logic for","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"isFullChunk()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":", ensuring it accurately evaluates capacity when elements span multiple dynamic priority groups or when the chunk limit is altered mid-lifecycle.","depth":26,"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":"AXHeading","text":"You said Are there any issues or potential bolltenecks","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":"Are there any issues or potential bolltenecks","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":"Based on the test diff you provided, we can infer a few potential issues and architectural bottlenecks in the underlying","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SelectionList","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"implementation. While the tests are well-structured, the behavior they describe hints at a few areas you might want to keep an eye on, particularly for an Elasticsearch (ES) processor queue.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Here are the potential issues and bottlenecks to consider:","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"1. Array Merging Overhead (Performance)","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1. Array Merging Overhead (Performance)","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"testAddEntityListMergesMultipleCallsForSamePriority","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"test shows that calling","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"addEntityList()","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"multiple times for the same priority group merges the arrays.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The Bottleneck:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"If the underlying implementation uses","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"array_merge()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"inside a loop to append these IDs, it creates a new array in memory every time it's called. If you are processing thousands of entities and appending them in small batches, this can lead to memory bloat and CPU degradation due to constant array reallocation.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Mitigation:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Ensure the implementation handles batch appends efficiently (e.g., using the spread operator","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"[...$existing, ...$new]","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"or appending via references) or groups the arrays before doing a single merge.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"2. Lack of Uniqueness/Deduplication (Logic)","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2. Lack of Uniqueness/Deduplication (Logic)","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"None of the tests explicitly verify what happens if duplicate IDs are added. For example, if you call","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"addEntityList(QueuePriorityEnum::HIGH, [1, 2])","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"and then","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"addEntityList(QueuePriorityEnum::HIGH, [2, 3])","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":".","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The Issue:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Does the getter return","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"[1, 2, 2, 3]","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"or","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"[1, 2, 3]","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"? If duplicates are not filtered out, your ES processor might end up indexing the same entity multiple times in a single chunk, which wastes I/O and processor cycles.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Mitigation:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The underlying class should ideally enforce uniqueness (e.g., using","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"array_unique()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"before resolving the chunk, or using ID keys as associative array keys to naturally prevent duplicates).","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"3. Memory Consumption with Large Chunks (Scalability)","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3. Memory Consumption with Large Chunks (Scalability)","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The tests introduce","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"setChunkSize()","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":". If this chunk size is configured to be very large (e.g., tens of thousands of IDs to bulk-send to Elasticsearch).","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The Bottleneck:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Holding massive arrays of IDs in memory across different priority groups can quickly hit PHP memory limits, especially if this","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SelectionList","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"object is kept alive during a long-running daemon or cron job.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Mitigation:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Monitor memory usage if","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"CHUNK_SIZE","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"grows, and ensure the","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SelectionList","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"object is properly destroyed (or garbage collected) after the chunk is processed to free up memory.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"4. Type Juggling","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"4. Type Juggling","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"In the original code, string IDs were used (","depth":24,"bounds":{"left":0.11336436,"top":0.0,"width":0.10139628,"height":0.016360734},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"['p1', 'p2']","depth":25,"bounds":{"left":0.21675532,"top":0.0,"width":0.03357713,"height":0.014764565},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"). In the refactored tests, integer IDs are used (","depth":24,"bounds":{"left":0.11336436,"top":0.0,"width":0.2365359,"height":0.038707104},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"[1, 2]","depth":25,"bounds":{"left":0.13048537,"top":0.0,"width":0.01662234,"height":0.014764565},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":").","depth":24,"bounds":{"left":0.14910239,"top":0.0,"width":0.0033244682,"height":0.016360734},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The Issue:","depth":26,"bounds":{"left":0.12599733,"top":0.0,"width":0.02642952,"height":0.016360734},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"If your system handles UUIDs (strings) vs. relational DB auto-increments (integers), make sure the underlying implementation uses strict comparisons (","depth":26,"bounds":{"left":0.12599733,"top":0.0,"width":0.22855718,"height":0.038707104},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"===","depth":27,"bounds":{"left":0.2897274,"top":0.002793296,"width":0.00831117,"height":0.014764565},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":") where necessary, especially if deduplicating arrays, to prevent PHP from juggling","depth":26,"bounds":{"left":0.12599733,"top":0.0015961692,"width":0.2209109,"height":0.038707104},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"'1'","depth":27,"bounds":{"left":0.2805851,"top":0.025139665,"width":0.00831117,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"and","depth":26,"bounds":{"left":0.29089096,"top":0.023942538,"width":0.011968086,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1","depth":27,"bounds":{"left":0.30485374,"top":0.025139665,"width":0.0026595744,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"improperly.","depth":26,"bounds":{"left":0.30950797,"top":0.023942538,"width":0.028424202,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Would you like me to draft a quick test case to check how the class currently handles duplicate IDs, or is deduplication intentionally handled further down your pipeline?","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.26180187,"top":0.1867518,"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.27642953,"top":0.1867518,"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 what about non test files","depth":21,"bounds":{"left":0.29637632,"top":0.19313647,"width":0.059674203,"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.19393456,"width":0.019946808,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"what about non test files","depth":23,"bounds":{"left":0.29637632,"top":0.19473264,"width":0.059674203,"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.2442139,"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.24660814,"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.28810853,"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.29010376,"width":0.04105718,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Since we don't have the actual","depth":24,"bounds":{"left":0.11336436,"top":0.29209897,"width":0.07513298,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SelectionList.php","depth":25,"bounds":{"left":0.19049202,"top":0.2932961,"width":0.047539894,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"file, we have to reverse-engineer its implementation based on the test behaviors. Moving from a constructor-based, fixed-property model to a dynamic, mutable model introduces several potential pitfalls in the implementation file itself.","depth":24,"bounds":{"left":0.11336436,"top":0.29209897,"width":0.24534574,"height":0.061053474},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Here are the specific bottlenecks and issues to watch out for in the","depth":24,"bounds":{"left":0.11336436,"top":0.367917,"width":0.16306517,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SelectionList.php","depth":25,"bounds":{"left":0.2784242,"top":0.36911413,"width":0.04737367,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"source code:","depth":24,"bounds":{"left":0.11336436,"top":0.367917,"width":0.23371011,"height":0.038707104},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"1. The count() Method Implementation (Performance Trap)","depth":23,"bounds":{"left":0.11336436,"top":0.43176377,"width":0.24534574,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1. The","depth":24,"bounds":{"left":0.11336436,"top":0.43335995,"width":0.016289894,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"count()","depth":25,"bounds":{"left":0.13164894,"top":0.43335995,"width":0.022273935,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Method Implementation (Performance Trap)","depth":24,"bounds":{"left":0.15591756,"top":0.43335995,"width":0.115192816,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The Risk:","depth":26,"bounds":{"left":0.12599733,"top":0.46049482,"width":0.023603724,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"If","depth":26,"bounds":{"left":0.14960106,"top":0.46049482,"width":0.005984043,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"count()","depth":27,"bounds":{"left":0.1575798,"top":0.46169195,"width":0.019614361,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"is implemented by calling","depth":26,"bounds":{"left":0.17918883,"top":0.46049482,"width":0.06333112,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$this->getAllIds()","depth":27,"bounds":{"left":0.24451463,"top":0.46169195,"width":0.05036569,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"and counting the resulting merged array (e.g.,","depth":26,"bounds":{"left":0.12599733,"top":0.46049482,"width":0.21459441,"height":0.038707104},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"return count($this->getAllIds());","depth":27,"bounds":{"left":0.19780585,"top":0.4840383,"width":0.09208777,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"), it will be highly inefficient. It would allocate a brand-new array in memory just to determine its length.","depth":26,"bounds":{"left":0.12599733,"top":0.4828412,"width":0.23271276,"height":0.038707104},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The Fix:","depth":26,"bounds":{"left":0.12599733,"top":0.5363129,"width":0.020279255,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"count()","depth":27,"bounds":{"left":0.14960106,"top":0.53751,"width":0.019614361,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"should mathematically sum the sizes of the underlying group arrays without merging them:","depth":26,"bounds":{"left":0.12599733,"top":0.5363129,"width":0.23055187,"height":0.038707104},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"return array_sum(array_map('count', $this->entityLists));","depth":27,"bounds":{"left":0.12799202,"top":0.58220273,"width":0.15924202,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"2. Loss of Immutability (State Management)","depth":23,"bounds":{"left":0.11336436,"top":0.62250596,"width":0.24534574,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2. Loss of Immutability (State Management)","depth":24,"bounds":{"left":0.11336436,"top":0.6241022,"width":0.11336436,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The Risk:","depth":26,"bounds":{"left":0.12599733,"top":0.651237,"width":0.023603724,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The original code passed all data via the constructor, implying the DTO (Data Transfer Object) was immutable once created. The refactored version introduces mutability (","depth":26,"bounds":{"left":0.12599733,"top":0.651237,"width":0.2322141,"height":0.061053474},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"addEntityList()","depth":27,"bounds":{"left":0.12982048,"top":0.6971269,"width":0.041888297,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":26,"bounds":{"left":0.17370346,"top":0.69592977,"width":0.0028257978,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"setChunkSize()","depth":27,"bounds":{"left":0.17852394,"top":0.6971269,"width":0.0390625,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":26,"bounds":{"left":0.21958111,"top":0.69592977,"width":0.0026595744,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"markStale()","depth":27,"bounds":{"left":0.22423537,"top":0.6971269,"width":0.030751329,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"). DTOs are typically passed between architectural layers; if one layer modifies the chunk size or adds entities while another is processing it, it can cause unpredictable side effects or race conditions in your queue processor.","depth":26,"bounds":{"left":0.12599733,"top":0.69592977,"width":0.22190824,"height":0.08339984},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The Fix:","depth":26,"bounds":{"left":0.12599733,"top":0.79409415,"width":0.020279255,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Ensure that this object is not shared across asynchronous contexts, or consider returning cloned instances when mutating state if strict immutability is required.","depth":26,"bounds":{"left":0.12599733,"top":0.79409415,"width":0.21459441,"height":0.038707104},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"3. Enum Array Key Violations (PHP Quirks)","depth":23,"bounds":{"left":0.11336436,"top":0.8579409,"width":0.24534574,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3. Enum Array Key Violations (PHP Quirks)","depth":24,"bounds":{"left":0.11336436,"top":0.8595371,"width":0.10854388,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The Risk:","depth":26,"bounds":{"left":0.12599733,"top":0.88667196,"width":0.023603724,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The tests show","depth":26,"bounds":{"left":0.14960106,"top":0.88667196,"width":0.0390625,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"QueuePriorityEnum::HIGH","depth":27,"bounds":{"left":0.19065824,"top":0.8878691,"width":0.06416223,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"being passed to methods. If the underlying code attempts to use this Enum directly as an array key (e.g.,","depth":26,"bounds":{"left":0.12599733,"top":0.88667196,"width":0.21027261,"height":0.038707104},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$this->lists[$priority] = $ids;","depth":27,"bounds":{"left":0.12599733,"top":0.9102155,"width":0.19414894,"height":0.037110932},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"), PHP will throw an error because objects (including Enums) cannot be used as standard array keys.","depth":26,"bounds":{"left":0.12599733,"top":0.9313647,"width":0.21858378,"height":0.038707104},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The Fix:","depth":26,"bounds":{"left":0.12599733,"top":0.9848364,"width":0.020279255,"height":0.0151636},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The implementation must map the Enum to its underlying scalar value (e.g.,","depth":26,"bounds":{"left":0.1462766,"top":0.9848364,"width":0.18351063,"height":0.0151636},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$this->lists[$priority->value]","depth":27,"bounds":{"left":0.12599733,"top":0.9860335,"width":0.22257313,"height":0.013966501},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":") or use PHP's","depth":26,"bounds":{"left":0.19498006,"top":1.0,"width":0.03507314,"height":-0.0071827173},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"WeakMap","depth":27,"bounds":{"left":0.23204787,"top":1.0,"width":0.019614361,"height":-0.008379936},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"or","depth":26,"bounds":{"left":0.25365692,"top":1.0,"width":0.0078125,"height":-0.0071827173},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SplObjectStorage","depth":27,"bounds":{"left":0.2634641,"top":1.0,"width":0.04454787,"height":-0.008379936},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":", though standard arrays using","depth":26,"bounds":{"left":0.12599733,"top":1.0,"width":0.22839096,"height":-0.0071827173},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$priority->value","depth":27,"bounds":{"left":0.15857713,"top":1.0,"width":0.044714097,"height":-0.030726314},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"are much faster for simple lists.","depth":26,"bounds":{"left":0.2052859,"top":1.0,"width":0.07679521,"height":-0.029529095},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"4. Uninitialized State Defaults (Logic Errors)","depth":23,"bounds":{"left":0.11336436,"top":1.0,"width":0.24534574,"height":-0.071029544},"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"4. Uninitialized State Defaults (Logic Errors)","depth":24,"bounds":{"left":0.11336436,"top":1.0,"width":0.11353058,"height":-0.072625756},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The Risk:","depth":26,"bounds":{"left":0.12599733,"top":1.0,"width":0.023603724,"height":-0.09976053},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The tests instantiate","depth":26,"bounds":{"left":0.14960106,"top":1.0,"width":0.051529255,"height":-0.09976053},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"new SelectionList()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"without arguments, then later call","depth":26,"bounds":{"left":0.25831118,"top":1.0,"width":0.08361037,"height":-0.09976053},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$selectionList->setChunkSize(100)","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":". If","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"isFullChunk()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"is called","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"before","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"setChunkSize()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"is invoked, what happens?","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The Fix:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Ensure","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SelectionList","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"has a sensible default for chunk size (e.g.,","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private int $chunkSize = 0;","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"or a system default) to prevent uninitialized property errors or division-by-zero scenarios if your logic ever relies on chunk math.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"5. getAllIds() Repeated Execution (CPU Overhead)","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"5.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"getAllIds()","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Repeated Execution (CPU Overhead)","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The Risk:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"If","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"getAllIds()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"dynamically merges arrays (","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"array_merge(...$this->lists)","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":") every time it is invoked, and your ES processor calls this method inside a loop, it will spike CPU usage.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The Fix:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"If the list is read frequently, the implementation should either cache the merged result and invalidate that cache when","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"addEntityList()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"is called, or the caller should assign the result to a local variable before iterating.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Would you like me to draft an optimal, memory-efficient skeleton for the","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SelectionList.php","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"implementation that avoids these specific pitfalls?","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Good response","depth":21,"on_screen":false,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false}]...
|
2267547230701554111
|
5896451135607762965
|
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
Copy prompt
You said I’m on page “<tabTitle>JY-20808 low priority indexing queue by Vasil-Jimi</tabTitle>” with “<selection>@@ -5,84 +5,140 @@5namespace Tests\Unit\Component\ES\Processor\DTOs;5namespace Tests\Unit\Component\ES\Processor\DTOs;667use Jiminny\Component\ES\Processor\DTOs\SelectionList;7use Jiminny\Component\ES\Processor\DTOs\SelectionList;8+use Jiminny\Component\ES\QueuePriorityEnum;8use PHPUnit\Framework\Attributes\CoversClass;9use PHPUnit\Framework\Attributes\CoversClass;9use PHPUnit\Framework\TestCase;10use PHPUnit\Framework\TestCase;101111#[CoversClass(SelectionList::class)]12#[CoversClass(SelectionList::class)]12final class SelectionListTest extends TestCase13final class SelectionListTest extends TestCase13{14{14-public function testGetEntityIds(): void15+private const int CHUNK_SIZE = 100;16+17+public function testAddEntityListAndGetAllIds(): void18+ {19+$selectionList = new SelectionList();20+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);21+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);22+23+$this->assertSame([1, 2, 3, 4], $selectionList->getAllIds());24+ }25+26+public function testAddEntityListMergesMultipleCallsForSamePriority(): void27+ {28+$selectionList = new SelectionList();29+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);30+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [3, 4]);31+32+$this->assertSame([1, 2, 3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));33+ }34+35+public function testGetEntityListItemsByGroup(): void36+ {37+$selectionList = new SelectionList();38+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);39+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);40+$selectionList->addEntityList(QueuePriorityEnum::LOW, [5, 6]);41+42+$this->assertSame([1, 2], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));43+$this->assertSame([3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::NORMAL));44+$this->assertSame([5, 6], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::LOW));45+ }46+47+public function testGetEntityListItemsByGroupReturnsEmptyArrayForUnknownGroup(): void15 {48 {16-$priority = ['p1', 'p2'];49+$selectionList = new SelectionList();17-$normal = ['n1', 'n2'];50+18-$selectionList = new SelectionList($priority, $normal);51+$this->assertSame([], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));52+ }195320-$this->assertSame($priority, $selectionList->getHighPriorityEntityIds());54+public function testGetEntityListGroups(): void21-$this->assertSame($normal, $selectionList->getNormalPriorityEntityId());55+ {56+$selectionList = new SelectionList();57+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);58+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2]);225923-$this->assertSame(['p1', 'p2', 'n1', 'n2'], $selectionList->getAllIds());60+$this->assertSame(['high', 'normal'], $selectionList->getEntityListGroups());24 }61 }256226public function testCountReturnsTotalCount(): void63public function testCountReturnsTotalCount(): void27 {64 {28-$selectionList = new SelectionList(['p1'], ['n1', 'n2']);65+$selectionList = new SelectionList();66+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);67+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2, 3]);68+29$this->assertSame(3, $selectionList->count());69$this->assertSame(3, $selectionList->count());30 }70 }317132-public function testIsEmptyReturnsTrueWhenBothListsAreEmpty(): void72+public function testIsEmptyReturnsTrueWhenNoEntitiesAdded(): void33 {73 {34-$selectionList = new SelectionList([], []);74+$selectionList = new SelectionList();75+35$this->assertTrue($selectionList->isEmpty());76$this->assertTrue($selectionList->isEmpty());36 }77 }377838-public function testIsEmptyReturnsFalseWhenAnyListIsNotEmpty(): void79+public function testIsEmptyReturnsFalseWhenEntitiesAdded(): void39 {80 {40-$selectionList = new SelectionList(['p1'], []);81+$selectionList = new SelectionList();41-$this->assertFalse($selectionList->isEmpty());82+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);428343-$selectionList2 = new SelectionList([], ['n1']);84+$this->assertFalse($selectionList->isEmpty());44-$this->assertFalse($selectionList2->isEmpty());45 }85 }468647-public function testIsStaleChunkSelected(): void87+public function testMarkStaleAndIsStaleChunkSelected(): void48 {88 {49-$selectionList = new SelectionList([], [], true);89+$selectionList = new SelectionList();50-$this->assertTrue($selectionList->isStaleChunkSelected());90+91+$this->assertFalse($selectionList->isStaleChunkSelected());92+93+$selectionList->markStale();519452-$selectionList2 = new SelectionList([], [], false);95+$this->assertTrue($selectionList->isStaleChunkSelected());53-$this->assertFalse($selectionList2->isStaleChunkSelected());54 }96 }559756public function testIsFullChunk(): void98public function testIsFullChunk(): void57 {99 {58-$chunkSize = 200;100+$selectionList = new SelectionList();59-101+$selectionList->setChunkSize(self::CHUNK_SIZE);60-$fullList = range(1, $chunkSize);102+61-$selectionList = new SelectionList(103+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, self::CHUNK_SIZE));62- priorityEntityIdList: $fullList,104+63- normalEntityIdList: [],105+$this->assertTrue($selectionList->isFullChunk());64- chunkSize: $chunkSize,106+ }65- );107+108+public function testIsNotFullChunkWhenBelowChunkSize(): void109+ {110+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);111+112+$selectionList = new SelectionList();113+$selectionList->setChunkSize(self::CHUNK_SIZE);114+115+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range(1, $halfRange));116+117+$this->assertFalse($selectionList->isFullChunk());118+ }119+120+public function testIsFullChunkAcrossMultiplePriorityGroups(): void121+ {122+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);123+124+$selectionList = new SelectionList();125+$selectionList->setChunkSize(self::CHUNK_SIZE);126+127+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, $halfRange));128+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range($halfRange + 1, self::CHUNK_SIZE));129+130+$this->assertTrue($selectionList->isFullChunk());131+ }132+133+public function testSetChunkSizeAffectsIsFullChunk(): void134+ {135+$selectionList = new SelectionList();136+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [1, 2, 3]);137+138+$selectionList->setChunkSize(3);66$this->assertTrue($selectionList->isFullChunk());139$this->assertTrue($selectionList->isFullChunk());6714068-$halfRange = (int) ceil($chunkSize / 2);141+$selectionList->setChunkSize(50);69-142+$this->assertFalse($selectionList->isFullChunk());70-$notFullList = range(1, $halfRange);71-$selectionList2 = new SelectionList(72- priorityEntityIdList: $notFullList,73- normalEntityIdList: [],74- chunkSize: $chunkSize,75- );76-$this->assertFalse($selectionList2->isFullChunk());77-78-$priorityRange = range(1, $halfRange);79-$normalRange = range($halfRange + 1, $chunkSize);80-81-$selectionList3 = new SelectionList(82- priorityEntityIdList: $priorityRange,83- normalEntityIdList: $normalRange,84- chunkSize: $chunkSize,85- );86-$this->assertTrue($selectionList3->isFullChunk());87 }143 }88}144}</selection>” selected. Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
You said
I’m on page “<tabTitle>JY-20808 low priority indexing queue by Vasil-Jimi</tabTitle>” with “<selection>@@ -5,84 +5,140 @@5namespace Tests\Unit\Component\ES\Processor\DTOs;5namespace Tests\Unit\Component\ES\Processor\DTOs;667use Jiminny\Component\ES\Processor\DTOs\SelectionList;7use Jiminny\Component\ES\Processor\DTOs\SelectionList;8+use Jiminny\Component\ES\QueuePriorityEnum;8use PHPUnit\Framework\Attributes\CoversClass;9use PHPUnit\Framework\Attributes\CoversClass;9use PHPUnit\Framework\TestCase;10use PHPUnit\Framework\TestCase;101111#[CoversClass(SelectionList::class)]12#[CoversClass(SelectionList::class)]12final class SelectionListTest extends TestCase13final class SelectionListTest extends TestCase13{14{14-public function testGetEntityIds(): void15+private const int CHUNK_SIZE = 100;16+17+public function testAddEntityListAndGetAllIds(): void18+ {19+$selectionList = new SelectionList();20+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);21+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);22+23+$this->assertSame([1, 2, 3, 4], $selectionList->getAllIds());24+ }25+26+public function testAddEntityListMergesMultipleCallsForSamePriority(): void27+ {28+$selectionList = new SelectionList();29+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);30+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [3, 4]);31+32+$this->assertSame([1, 2, 3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));33+ }34+35+public function testGetEntityListItemsByGroup(): void36+ {37+$selectionList = new SelectionList();38+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);39+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);40+$selectionList->addEntityList(QueuePriorityEnum::LOW, [5, 6]);41+42+$this->assertSame([1, 2], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));43+$this->assertSame([3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::NORMAL));44+$this->assertSame([5, 6], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::LOW));45+ }46+47+public function testGetEntityListItemsByGroupReturnsEmptyArrayForUnknownGroup(): void15 {48 {16-$priority = ['p1', 'p2'];49+$selectionList = new SelectionList();17-$normal = ['n1', 'n2'];50+18-$selectionList = new SelectionList($priority, $normal);51+$this->assertSame([], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));52+ }195320-$this->assertSame($priority, $selectionList->getHighPriorityEntityIds());54+public function testGetEntityListGroups(): void21-$this->assertSame($normal, $selectionList->getNormalPriorityEntityId());55+ {56+$selectionList = new SelectionList();57+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);58+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2]);225923-$this->assertSame(['p1', 'p2', 'n1', 'n2'], $selectionList->getAllIds());60+$this->assertSame(['high', 'normal'], $selectionList->getEntityListGroups());24 }61 }256226public function testCountReturnsTotalCount(): void63public function testCountReturnsTotalCount(): void27 {64 {28-$selectionList = new SelectionList(['p1'], ['n1', 'n2']);65+$selectionList = new SelectionList();66+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);67+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2, 3]);68+29$this->assertSame(3, $selectionList->count());69$this->assertSame(3, $selectionList->count());30 }70 }317132-public function testIsEmptyReturnsTrueWhenBothListsAreEmpty(): void72+public function testIsEmptyReturnsTrueWhenNoEntitiesAdded(): void33 {73 {34-$selectionList = new SelectionList([], []);74+$selectionList = new SelectionList();75+35$this->assertTrue($selectionList->isEmpty());76$this->assertTrue($selectionList->isEmpty());36 }77 }377838-public function testIsEmptyReturnsFalseWhenAnyListIsNotEmpty(): void79+public function testIsEmptyReturnsFalseWhenEntitiesAdded(): void39 {80 {40-$selectionList = new SelectionList(['p1'], []);81+$selectionList = new SelectionList();41-$this->assertFalse($selectionList->isEmpty());82+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);428343-$selectionList2 = new SelectionList([], ['n1']);84+$this->assertFalse($selectionList->isEmpty());44-$this->assertFalse($selectionList2->isEmpty());45 }85 }468647-public function testIsStaleChunkSelected(): void87+public function testMarkStaleAndIsStaleChunkSelected(): void48 {88 {49-$selectionList = new SelectionList([], [], true);89+$selectionList = new SelectionList();50-$this->assertTrue($selectionList->isStaleChunkSelected());90+91+$this->assertFalse($selectionList->isStaleChunkSelected());92+93+$selectionList->markStale();519452-$selectionList2 = new SelectionList([], [], false);95+$this->assertTrue($selectionList->isStaleChunkSelected());53-$this->assertFalse($selectionList2->isStaleChunkSelected());54 }96 }559756public function testIsFullChunk(): void98public function testIsFullChunk(): void57 {99 {58-$chunkSize = 200;100+$selectionList = new SelectionList();59-101+$selectionList->setChunkSize(self::CHUNK_SIZE);60-$fullList = range(1, $chunkSize);102+61-$selectionList = new SelectionList(103+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, self::CHUNK_SIZE));62- priorityEntityIdList: $fullList,104+63- normalEntityIdList: [],105+$this->assertTrue($selectionList->isFullChunk());64- chunkSize: $chunkSize,106+ }65- );107+108+public function testIsNotFullChunkWhenBelowChunkSize(): void109+ {110+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);111+112+$selectionList = new SelectionList();113+$selectionList->setChunkSize(self::CHUNK_SIZE);114+115+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range(1, $halfRange));116+117+$this->assertFalse($selectionList->isFullChunk());118+ }119+120+public function testIsFullChunkAcrossMultiplePriorityGroups(): void121+ {122+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);123+124+$selectionList = new SelectionList();125+$selectionList->setChunkSize(self::CHUNK_SIZE);126+127+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, $halfRange));128+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range($halfRange + 1, self::CHUNK_SIZE));129+130+$this->assertTrue($selectionList->isFullChunk());131+ }132+133+public function testSetChunkSizeAffectsIsFullChunk(): void134+ {135+$selectionList = new SelectionList();136+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [1, 2, 3]);137+138+$selectionList->setChunkSize(3);66$this->assertTrue($selectionList->isFullChunk());139$this->assertTrue($selectionList->isFullChunk());6714068-$halfRange = (int) ceil($chunkSize / 2);141+$selectionList->setChunkSize(50);69-142+$this->assertFalse($selectionList->isFullChunk());70-$notFullList = range(1, $halfRange);71-$selectionList2 = new SelectionList(72- priorityEntityIdList: $notFullList,73- normalEntityIdList: [],74- chunkSize: $chunkSize,75- );76-$this->assertFalse($selectionList2->isFullChunk());77-78-$priorityRange = range(1, $halfRange);79-$normalRange = range($halfRange + 1, $chunkSize);80-81-$selectionList3 = new SelectionList(82- priorityEntityIdList: $priorityRange,83- normalEntityIdList: $normalRange,84- chunkSize: $chunkSize,85- );86-$this->assertTrue($selectionList3->isFullChunk());87 }143 }88}144}</selection>” selected.
Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
Expand
Listen
Gemini said
Gemini said
Here is a precise and concise summary of the code selection, which refactors
SelectionListTest
to accommodate a shift from fixed high/normal priority properties to a more dynamic, enum-driven priority group architecture.
Refactored Priority Handling
Refactored Priority Handling
Dynamic Priority Groups:
Replaces fixed high/normal array parameters with the
QueuePriorityEnum
(
HIGH
,
NORMAL
,
LOW
), allowing entity lists to be managed dynamically by group types.
Merged Registrations:
Validates that multiple
addEntityList()
calls targeting the same priority level properly merge their data instead of overwriting it.
Group Querying:
Tests new methods
getEntityListItemsByGroup()
and
getEntityListGroups()
to retrieve group-specific IDs or an array of active group names (e.g.,
['high', 'normal']
).
Updated State and Count Validations
Updated State and Count Validations
Instantiation:
Tests now instantiate
SelectionList
without initial constructor arguments, using setters and action methods instead.
Empty States:
Updates assertions (
isEmpty()
) to verify state based on whether any entities have been dynamically added, rather than checking pre-defined constructor arrays.
Stale Flags:
Changes from passing a
stale
boolean via the constructor to explicitly triggering a mutable
$selectionList->markStale()
method.
Chunk Capacity Behavior
Chunk Capacity Behavior
Flexible Chunk Sizes:
Introduces a
setChunkSize()
method, replacing the constructor-configured chunk boundary.
Capacity Assertions:
Retains and updates the logic for
isFullChunk()
, ensuring it accurately evaluates capacity when elements span multiple dynamic priority groups or when the chunk limit is altered mid-lifecycle.
Good response
Bad response
Share & export
Copy
Show more options
Copy prompt
You said Are there any issues or potential bolltenecks
You said
Are there any issues or potential bolltenecks
Listen
Show thinking
Gemini said
Gemini said
Based on the test diff you provided, we can infer a few potential issues and architectural bottlenecks in the underlying
SelectionList
implementation. While the tests are well-structured, the behavior they describe hints at a few areas you might want to keep an eye on, particularly for an Elasticsearch (ES) processor queue.
Here are the potential issues and bottlenecks to consider:
1. Array Merging Overhead (Performance)
1. Array Merging Overhead (Performance)
The
testAddEntityListMergesMultipleCallsForSamePriority
test shows that calling
addEntityList()
multiple times for the same priority group merges the arrays.
The Bottleneck:
If the underlying implementation uses
array_merge()
inside a loop to append these IDs, it creates a new array in memory every time it's called. If you are processing thousands of entities and appending them in small batches, this can lead to memory bloat and CPU degradation due to constant array reallocation.
Mitigation:
Ensure the implementation handles batch appends efficiently (e.g., using the spread operator
[...$existing, ...$new]
or appending via references) or groups the arrays before doing a single merge.
2. Lack of Uniqueness/Deduplication (Logic)
2. Lack of Uniqueness/Deduplication (Logic)
None of the tests explicitly verify what happens if duplicate IDs are added. For example, if you call
addEntityList(QueuePriorityEnum::HIGH, [1, 2])
and then
addEntityList(QueuePriorityEnum::HIGH, [2, 3])
.
The Issue:
Does the getter return
[1, 2, 2, 3]
or
[1, 2, 3]
? If duplicates are not filtered out, your ES processor might end up indexing the same entity multiple times in a single chunk, which wastes I/O and processor cycles.
Mitigation:
The underlying class should ideally enforce uniqueness (e.g., using
array_unique()
before resolving the chunk, or using ID keys as associative array keys to naturally prevent duplicates).
3. Memory Consumption with Large Chunks (Scalability)
3. Memory Consumption with Large Chunks (Scalability)
The tests introduce
setChunkSize()
. If this chunk size is configured to be very large (e.g., tens of thousands of IDs to bulk-send to Elasticsearch).
The Bottleneck:
Holding massive arrays of IDs in memory across different priority groups can quickly hit PHP memory limits, especially if this
SelectionList
object is kept alive during a long-running daemon or cron job.
Mitigation:
Monitor memory usage if
CHUNK_SIZE
grows, and ensure the
SelectionList
object is properly destroyed (or garbage collected) after the chunk is processed to free up memory.
4. Type Juggling
4. Type Juggling
In the original code, string IDs were used (
['p1', 'p2']
). In the refactored tests, integer IDs are used (
[1, 2]
).
The Issue:
If your system handles UUIDs (strings) vs. relational DB auto-increments (integers), make sure the underlying implementation uses strict comparisons (
===
) where necessary, especially if deduplicating arrays, to prevent PHP from juggling
'1'
and
1
improperly.
Would you like me to draft a quick test case to check how the class currently handles duplicate IDs, or is deduplication intentionally handled further down your pipeline?
Good response
Bad response
Share & export
Copy
Show more options
Copy prompt
Edit
You said what about non test files
You said
what about non test files
Listen
Show thinking
Gemini said
Gemini said
Since we don't have the actual
SelectionList.php
file, we have to reverse-engineer its implementation based on the test behaviors. Moving from a constructor-based, fixed-property model to a dynamic, mutable model introduces several potential pitfalls in the implementation file itself.
Here are the specific bottlenecks and issues to watch out for in the
SelectionList.php
source code:
1. The count() Method Implementation (Performance Trap)
1. The
count()
Method Implementation (Performance Trap)
The Risk:
If
count()
is implemented by calling
$this->getAllIds()
and counting the resulting merged array (e.g.,
return count($this->getAllIds());
), it will be highly inefficient. It would allocate a brand-new array in memory just to determine its length.
The Fix:
count()
should mathematically sum the sizes of the underlying group arrays without merging them:
return array_sum(array_map('count', $this->entityLists));
2. Loss of Immutability (State Management)
2. Loss of Immutability (State Management)
The Risk:
The original code passed all data via the constructor, implying the DTO (Data Transfer Object) was immutable once created. The refactored version introduces mutability (
addEntityList()
,
setChunkSize()
,
markStale()
). DTOs are typically passed between architectural layers; if one layer modifies the chunk size or adds entities while another is processing it, it can cause unpredictable side effects or race conditions in your queue processor.
The Fix:
Ensure that this object is not shared across asynchronous contexts, or consider returning cloned instances when mutating state if strict immutability is required.
3. Enum Array Key Violations (PHP Quirks)
3. Enum Array Key Violations (PHP Quirks)
The Risk:
The tests show
QueuePriorityEnum::HIGH
being passed to methods. If the underlying code attempts to use this Enum directly as an array key (e.g.,
$this->lists[$priority] = $ids;
), PHP will throw an error because objects (including Enums) cannot be used as standard array keys.
The Fix:
The implementation must map the Enum to its underlying scalar value (e.g.,
$this->lists[$priority->value]
) or use PHP's
WeakMap
or
SplObjectStorage
, though standard arrays using
$priority->value
are much faster for simple lists.
4. Uninitialized State Defaults (Logic Errors)
4. Uninitialized State Defaults (Logic Errors)
The Risk:
The tests instantiate
new SelectionList()
without arguments, then later call
$selectionList->setChunkSize(100)
. If
isFullChunk()
is called
before
setChunkSize()
is invoked, what happens?
The Fix:
Ensure
SelectionList
has a sensible default for chunk size (e.g.,
private int $chunkSize = 0;
or a system default) to prevent uninitialized property errors or division-by-zero scenarios if your logic ever relies on chunk math.
5. getAllIds() Repeated Execution (CPU Overhead)
5.
getAllIds()
Repeated Execution (CPU Overhead)
The Risk:
If
getAllIds()
dynamically merges arrays (
array_merge(...$this->lists)
) every time it is invoked, and your ES processor calls this method inside a loop, it will spike CPU usage.
The Fix:
If the list is read frequently, the implementation should either cache the merged result and invalidate that cache when
addEntityList()
is called, or the caller should assign the result to a local variable before iterating.
Would you like me to draft an optimal, memory-efficient skeleton for the
SelectionList.php
implementation that avoids these specific pitfalls?
Good response...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
55655
|
1931
|
18
|
2026-05-19T06:35:44.125761+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779172544125_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
Copy prompt
You said I’m on page “<tabTitle>JY-20808 low priority indexing queue by Vasil-Jimi</tabTitle>” with “<selection>@@ -5,84 +5,140 @@5namespace Tests\Unit\Component\ES\Processor\DTOs;5namespace Tests\Unit\Component\ES\Processor\DTOs;667use Jiminny\Component\ES\Processor\DTOs\SelectionList;7use Jiminny\Component\ES\Processor\DTOs\SelectionList;8+use Jiminny\Component\ES\QueuePriorityEnum;8use PHPUnit\Framework\Attributes\CoversClass;9use PHPUnit\Framework\Attributes\CoversClass;9use PHPUnit\Framework\TestCase;10use PHPUnit\Framework\TestCase;101111#[CoversClass(SelectionList::class)]12#[CoversClass(SelectionList::class)]12final class SelectionListTest extends TestCase13final class SelectionListTest extends TestCase13{14{14-public function testGetEntityIds(): void15+private const int CHUNK_SIZE = 100;16+17+public function testAddEntityListAndGetAllIds(): void18+ {19+$selectionList = new SelectionList();20+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);21+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);22+23+$this->assertSame([1, 2, 3, 4], $selectionList->getAllIds());24+ }25+26+public function testAddEntityListMergesMultipleCallsForSamePriority(): void27+ {28+$selectionList = new SelectionList();29+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);30+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [3, 4]);31+32+$this->assertSame([1, 2, 3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));33+ }34+35+public function testGetEntityListItemsByGroup(): void36+ {37+$selectionList = new SelectionList();38+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);39+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);40+$selectionList->addEntityList(QueuePriorityEnum::LOW, [5, 6]);41+42+$this->assertSame([1, 2], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));43+$this->assertSame([3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::NORMAL));44+$this->assertSame([5, 6], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::LOW));45+ }46+47+public function testGetEntityListItemsByGroupReturnsEmptyArrayForUnknownGroup(): void15 {48 {16-$priority = ['p1', 'p2'];49+$selectionList = new SelectionList();17-$normal = ['n1', 'n2'];50+18-$selectionList = new SelectionList($priority, $normal);51+$this->assertSame([], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));52+ }195320-$this->assertSame($priority, $selectionList->getHighPriorityEntityIds());54+public function testGetEntityListGroups(): void21-$this->assertSame($normal, $selectionList->getNormalPriorityEntityId());55+ {56+$selectionList = new SelectionList();57+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);58+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2]);225923-$this->assertSame(['p1', 'p2', 'n1', 'n2'], $selectionList->getAllIds());60+$this->assertSame(['high', 'normal'], $selectionList->getEntityListGroups());24 }61 }256226public function testCountReturnsTotalCount(): void63public function testCountReturnsTotalCount(): void27 {64 {28-$selectionList = new SelectionList(['p1'], ['n1', 'n2']);65+$selectionList = new SelectionList();66+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);67+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2, 3]);68+29$this->assertSame(3, $selectionList->count());69$this->assertSame(3, $selectionList->count());30 }70 }317132-public function testIsEmptyReturnsTrueWhenBothListsAreEmpty(): void72+public function testIsEmptyReturnsTrueWhenNoEntitiesAdded(): void33 {73 {34-$selectionList = new SelectionList([], []);74+$selectionList = new SelectionList();75+35$this->assertTrue($selectionList->isEmpty());76$this->assertTrue($selectionList->isEmpty());36 }77 }377838-public function testIsEmptyReturnsFalseWhenAnyListIsNotEmpty(): void79+public function testIsEmptyReturnsFalseWhenEntitiesAdded(): void39 {80 {40-$selectionList = new SelectionList(['p1'], []);81+$selectionList = new SelectionList();41-$this->assertFalse($selectionList->isEmpty());82+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);428343-$selectionList2 = new SelectionList([], ['n1']);84+$this->assertFalse($selectionList->isEmpty());44-$this->assertFalse($selectionList2->isEmpty());45 }85 }468647-public function testIsStaleChunkSelected(): void87+public function testMarkStaleAndIsStaleChunkSelected(): void48 {88 {49-$selectionList = new SelectionList([], [], true);89+$selectionList = new SelectionList();50-$this->assertTrue($selectionList->isStaleChunkSelected());90+91+$this->assertFalse($selectionList->isStaleChunkSelected());92+93+$selectionList->markStale();519452-$selectionList2 = new SelectionList([], [], false);95+$this->assertTrue($selectionList->isStaleChunkSelected());53-$this->assertFalse($selectionList2->isStaleChunkSelected());54 }96 }559756public function testIsFullChunk(): void98public function testIsFullChunk(): void57 {99 {58-$chunkSize = 200;100+$selectionList = new SelectionList();59-101+$selectionList->setChunkSize(self::CHUNK_SIZE);60-$fullList = range(1, $chunkSize);102+61-$selectionList = new SelectionList(103+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, self::CHUNK_SIZE));62- priorityEntityIdList: $fullList,104+63- normalEntityIdList: [],105+$this->assertTrue($selectionList->isFullChunk());64- chunkSize: $chunkSize,106+ }65- );107+108+public function testIsNotFullChunkWhenBelowChunkSize(): void109+ {110+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);111+112+$selectionList = new SelectionList();113+$selectionList->setChunkSize(self::CHUNK_SIZE);114+115+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range(1, $halfRange));116+117+$this->assertFalse($selectionList->isFullChunk());118+ }119+120+public function testIsFullChunkAcrossMultiplePriorityGroups(): void121+ {122+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);123+124+$selectionList = new SelectionList();125+$selectionList->setChunkSize(self::CHUNK_SIZE);126+127+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, $halfRange));128+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range($halfRange + 1, self::CHUNK_SIZE));129+130+$this->assertTrue($selectionList->isFullChunk());131+ }132+133+public function testSetChunkSizeAffectsIsFullChunk(): void134+ {135+$selectionList = new SelectionList();136+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [1, 2, 3]);137+138+$selectionList->setChunkSize(3);66$this->assertTrue($selectionList->isFullChunk());139$this->assertTrue($selectionList->isFullChunk());6714068-$halfRange = (int) ceil($chunkSize / 2);141+$selectionList->setChunkSize(50);69-142+$this->assertFalse($selectionList->isFullChunk());70-$notFullList = range(1, $halfRange);71-$selectionList2 = new SelectionList(72- priorityEntityIdList: $notFullList,73- normalEntityIdList: [],74- chunkSize: $chunkSize,75- );76-$this->assertFalse($selectionList2->isFullChunk());77-78-$priorityRange = range(1, $halfRange);79-$normalRange = range($halfRange + 1, $chunkSize);80-81-$selectionList3 = new SelectionList(82- priorityEntityIdList: $priorityRange,83- normalEntityIdList: $normalRange,84- chunkSize: $chunkSize,85- );86-$this->assertTrue($selectionList3->isFullChunk());87 }143 }88}144}</selection>” selected. Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
You said
I’m on page “<tabTitle>JY-20808 low priority indexing queue by Vasil-Jimi</tabTitle>” with “<selection>@@ -5,84 +5,140 @@5namespace Tests\Unit\Component\ES\Processor\DTOs;5namespace Tests\Unit\Component\ES\Processor\DTOs;667use Jiminny\Component\ES\Processor\DTOs\SelectionList;7use Jiminny\Component\ES\Processor\DTOs\SelectionList;8+use Jiminny\Component\ES\QueuePriorityEnum;8use PHPUnit\Framework\Attributes\CoversClass;9use PHPUnit\Framework\Attributes\CoversClass;9use PHPUnit\Framework\TestCase;10use PHPUnit\Framework\TestCase;101111#[CoversClass(SelectionList::class)]12#[CoversClass(SelectionList::class)]12final class SelectionListTest extends TestCase13final class SelectionListTest extends TestCase13{14{14-public function testGetEntityIds(): void15+private const int CHUNK_SIZE = 100;16+17+public function testAddEntityListAndGetAllIds(): void18+ {19+$selectionList = new SelectionList();20+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);21+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);22+23+$this->assertSame([1, 2, 3, 4], $selectionList->getAllIds());24+ }25+26+public function testAddEntityListMergesMultipleCallsForSamePriority(): void27+ {28+$selectionList = new SelectionList();29+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);30+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [3, 4]);31+32+$this->assertSame([1, 2, 3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));33+ }34+35+public function testGetEntityListItemsByGroup(): void36+ {37+$selectionList = new SelectionList();38+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);39+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);40+$selectionList->addEntityList(QueuePriorityEnum::LOW, [5, 6]);41+42+$this->assertSame([1, 2], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));43+$this->assertSame([3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::NORMAL));44+$this->assertSame([5, 6], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::LOW));45+ }46+47+public function testGetEntityListItemsByGroupReturnsEmptyArrayForUnknownGroup(): void15 {48 {16-$priority = ['p1', 'p2'];49+$selectionList = new SelectionList();17-$normal = ['n1', 'n2'];50+18-$selectionList = new SelectionList($priority, $normal);51+$this->assertSame([], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));52+ }195320-$this->assertSame($priority, $selectionList->getHighPriorityEntityIds());54+public function testGetEntityListGroups(): void21-$this->assertSame($normal, $selectionList->getNormalPriorityEntityId());55+ {56+$selectionList = new SelectionList();57+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);58+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2]);225923-$this->assertSame(['p1', 'p2', 'n1', 'n2'], $selectionList->getAllIds());60+$this->assertSame(['high', 'normal'], $selectionList->getEntityListGroups());24 }61 }256226public function testCountReturnsTotalCount(): void63public function testCountReturnsTotalCount(): void27 {64 {28-$selectionList = new SelectionList(['p1'], ['n1', 'n2']);65+$selectionList = new SelectionList();66+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);67+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2, 3]);68+29$this->assertSame(3, $selectionList->count());69$this->assertSame(3, $selectionList->count());30 }70 }317132-public function testIsEmptyReturnsTrueWhenBothListsAreEmpty(): void72+public function testIsEmptyReturnsTrueWhenNoEntitiesAdded(): void33 {73 {34-$selectionList = new SelectionList([], []);74+$selectionList = new SelectionList();75+35$this->assertTrue($selectionList->isEmpty());76$this->assertTrue($selectionList->isEmpty());36 }77 }377838-public function testIsEmptyReturnsFalseWhenAnyListIsNotEmpty(): void79+public function testIsEmptyReturnsFalseWhenEntitiesAdded(): void39 {80 {40-$selectionList = new SelectionList(['p1'], []);81+$selectionList = new SelectionList();41-$this->assertFalse($selectionList->isEmpty());82+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);428343-$selectionList2 = new SelectionList([], ['n1']);84+$this->assertFalse($selectionList->isEmpty());44-$this->assertFalse($selectionList2->isEmpty());45 }85 }468647-public function testIsStaleChunkSelected(): void87+public function testMarkStaleAndIsStaleChunkSelected(): void48 {88 {49-$selectionList = new SelectionList([], [], true);89+$selectionList = new SelectionList();50-$this->assertTrue($selectionList->isStaleChunkSelected());90+91+$this->assertFalse($selectionList->isStaleChunkSelected());92+93+$selectionList->markStale();519452-$selectionList2 = new SelectionList([], [], false);95+$this->assertTrue($selectionList->isStaleChunkSelected());53-$this->assertFalse($selectionList2->isStaleChunkSelected());54 }96 }559756public function testIsFullChunk(): void98public function testIsFullChunk(): void57 {99 {58-$chunkSize = 200;100+$selectionList = new SelectionList();59-101+$selectionList->setChunkSize(self::CHUNK_SIZE);60-$fullList = range(1, $chunkSize);102+61-$selectionList = new SelectionList(103+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, self::CHUNK_SIZE));62- priorityEntityIdList: $fullList,104+63- normalEntityIdList: [],105+$this->assertTrue($selectionList->isFullChunk());64- chunkSize: $chunkSize,106+ }65- );107+108+public function testIsNotFullChunkWhenBelowChunkSize(): void109+ {110+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);111+112+$selectionList = new SelectionList();113+$selectionList->setChunkSize(self::CHUNK_SIZE);114+115+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range(1, $halfRange));116+117+$this->assertFalse($selectionList->isFullChunk());118+ }119+120+public function testIsFullChunkAcrossMultiplePriorityGroups(): void121+ {122+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);123+124+$selectionList = new SelectionList();125+$selectionList->setChunkSize(self::CHUNK_SIZE);126+127+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, $halfRange));128+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range($halfRange + 1, self::CHUNK_SIZE));129+130+$this->assertTrue($selectionList->isFullChunk());131+ }132+133+public function testSetChunkSizeAffectsIsFullChunk(): void134+ {135+$selectionList = new SelectionList();136+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [1, 2, 3]);137+138+$selectionList->setChunkSize(3);66$this->assertTrue($selectionList->isFullChunk());139$this->assertTrue($selectionList->isFullChunk());6714068-$halfRange = (int) ceil($chunkSize / 2);141+$selectionList->setChunkSize(50);69-142+$this->assertFalse($selectionList->isFullChunk());70-$notFullList = range(1, $halfRange);71-$selectionList2 = new SelectionList(72- priorityEntityIdList: $notFullList,73- normalEntityIdList: [],74- chunkSize: $chunkSize,75- );76-$this->assertFalse($selectionList2->isFullChunk());77-78-$priorityRange = range(1, $halfRange);79-$normalRange = range($halfRange + 1, $chunkSize);80-81-$selectionList3 = new SelectionList(82- priorityEntityIdList: $priorityRange,83- normalEntityIdList: $normalRange,84- chunkSize: $chunkSize,85- );86-$this->assertTrue($selectionList3->isFullChunk());87 }143 }88}144}</selection>” selected.
Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
Expand
Listen
Gemini said
Gemini said
Here is a precise and concise summary of the code selection, which refactors
SelectionListTest
to accommodate a shift from fixed high/normal priority properties to a more dynamic, enum-driven priority group architecture.
Refactored Priority Handling
Refactored Priority Handling
Dynamic Priority Groups:
Replaces fixed high/normal array parameters with the
QueuePriorityEnum
(
HIGH
,
NORMAL
,
LOW
), allowing entity lists to be managed dynamically by group types.
Merged Registrations:
Validates that multiple
addEntityList()
calls targeting the same priority level properly merge their data instead of overwriting it.
Group Querying:
Tests new methods
getEntityListItemsByGroup()
and
getEntityListGroups()
to retrieve group-specific IDs or an array of active group names (e.g.,
['high', 'normal']
).
Updated State and Count Validations
Updated State and Count Validations
Instantiation:
Tests now instantiate
SelectionList
without initial constructor arguments, using setters and action methods instead.
Empty States:
Updates assertions (
isEmpty()
) to verify state based on whether any entities have been dynamically added, rather than checking pre-defined constructor arrays.
Stale Flags:
Changes from passing a
stale
boolean via the constructor to explicitly triggering a mutable
$selectionList->markStale()
method.
Chunk Capacity Behavior
Chunk Capacity Behavior
Flexible Chunk Sizes:
Introduces a
setChunkSize()
method, replacing the constructor-configured chunk boundary.
Capacity Assertions:
Retains and updates the logic for
isFullChunk()
, ensuring it accurately evaluates capacity when elements span multiple dynamic priority groups or when the chunk limit is altered mid-lifecycle.
Good response
Bad response
Share & export
Copy
Show more options
Copy prompt
You said Are there any issues or potential bolltenecks
You said
Are there any issues or potential bolltenecks
Listen
Show thinking
Gemini said
Gemini said
Based on the test diff you provided, we can infer a few potential issues and architectural bottlenecks in the underlying
SelectionList
implementation. While the tests are well-structured, the behavior they describe hints at a few areas you might want to keep an eye on, particularly for an Elasticsearch (ES) processor queue.
Here are the potential issues and bottlenecks to consider:
1. Array Merging Overhead (Performance)
1. Array Merging Overhead (Performance)
The
testAddEntityListMergesMultipleCallsForSamePriority
test shows that calling
addEntityList()
multiple times for the same priority group merges the arrays.
The Bottleneck:
If the underlying implementation uses
array_merge()
inside a loop to append these IDs, it creates a new array in memory every time it's called. If you are processing thousands of entities and appending them in small batches, this can lead to memory bloat and CPU degradation due to constant array reallocation.
Mitigation:
Ensure the implementation handles batch appends efficiently (e.g., using the spread operator
[...$existing, ...$new]
or appending via references) or groups the arrays before doing a single merge.
2. Lack of Uniqueness/Deduplication (Logic)
2. Lack of Uniqueness/Deduplication (Logic)
None of the tests explicitly verify what happens if duplicate IDs are added. For example, if you call
addEntityList(QueuePriorityEnum::HIGH, [1, 2])
and then
addEntityList(QueuePriorityEnum::HIGH, [2, 3])
.
The Issue:
Does the getter return
[1, 2, 2, 3]
or
[1, 2, 3]
? If duplicates are not filtered out, your ES processor might end up indexing the same entity multiple times in a single chunk, which wastes I/O and processor cycles.
Mitigation:
The underlying class should ideally enforce uniqueness (e.g., using
array_unique()
before resolving the chunk, or using ID keys as associative array keys to naturally prevent duplicates).
3. Memory Consumption with Large Chunks (Scalability)
3. Memory Consumption with Large Chunks (Scalability)
The tests introduce
setChunkSize()
. If this chunk size is configured to be very large (e.g., tens of thousands of IDs to bulk-send to Elasticsearch).
The Bottleneck:
Holding massive arrays of IDs in memory across different priority groups can quickly hit PHP memory limits, especially if this
SelectionList
object is kept alive during a long-running daemon or cron job.
Mitigation:
Monitor memory usage if
CHUNK_SIZE
grows, and ensure the
SelectionList
object is properly destroyed (or garbage collected) after the chunk is processed to free up memory.
4. Type Juggling
4. Type Juggling
In the original code, string IDs were used (
['p1', 'p2']
). In the refactored tests, integer IDs are used (
[1, 2]
).
The Issue:
If your system handles UUIDs (strings) vs. relational DB auto-increments (integers), make sure the underlying implementation uses strict comparisons (
===
) where necessary, especially if deduplicating arrays, to prevent PHP from juggling
'1'
and
1
improperly.
Would you like me to draft a quick test case to check how the class currently handles duplicate IDs, or is deduplication intentionally handled further down your pipeline?
Good response
Bad response
Share & export
Copy
Show more options
Copy prompt
You said what about non test files
You said
what about non test files
Listen
Show thinking
Gemini said
Gemini said
Since we don't have the actual
SelectionList.php
file, we have to reverse-engineer its implementation based on the test behaviors. Moving from a constructor-based, fixed-property model to a dynamic, mutable model introduces several potential pitfalls in the implementation file itself.
Here are the specific bottlenecks and issues to watch out for in the
SelectionList.php
source code:
1. The count() Method Implementation (Performance Trap)
1. The
count()
Method Implementation (Performance Trap)
The Risk:
If
count()
is implemented by calling
$this->getAllIds()
and counting the resulting merged array (e.g.,
return count($this->getAllIds());
), it will be highly inefficient. It would allocate a brand-new array in memory just to determine its length.
The Fix:
count()
should mathematically sum the sizes of the underlying group arrays without merging them:
return array_sum(array_map('count', $this->entityLists));
2. Loss of Immutability (State Management)
2. Loss of Immutability (State Management)
The Risk:
The original code passed all data via the constructor, implying the DTO (Data Transfer Object) was immutable once created. The refactored version introduces mutability (
addEntityList()
,
setChunkSize()
,
markStale()
). DTOs are typically passed between architectural layers; if one layer modifies the chunk size or adds entities while another is processing it, it can cause unpredictable side effects or race conditions in your queue processor.
The Fix:
Ensure that this object is not shared across asynchronous contexts, or consider returning cloned instances when mutating state if strict immutability is required.
3. Enum Array Key Violations (PHP Quirks)
3. Enum Array Key Violations (PHP Quirks)
The Risk:
The tests show
QueuePriorityEnum::HIGH
being passed to methods. If the underlying code attempts to use this Enum directly as an array key (e.g.,
$this->lists[$priority] = $ids;
), PHP will throw an error because objects (including Enums) cannot be used as standard array keys.
The Fix:
The implementation must map the Enum to its underlying scalar value (e.g.,
$this->lists[$priority->value]
) or use PHP's
WeakMap
or
SplObjectStorage
, though standard arrays using
$priority->value
are much faster for simple lists.
4. Uninitialized State Defaults (Logic Errors)
4. Uninitialized State Defaults (Logic Errors)
The Risk:
The tests instantiate
new SelectionList()
without arguments, then later call
$selectionList->setChunkSize(100)
. If
isFullChunk()
is called
before
setChunkSize()
is invoked, what happens?
The Fix:
Ensure
SelectionList
has a sensible default for chunk size (e.g.,
private int $chunkSize = 0;
or a system default) to prevent uninitialized property errors or division-by-zero scenarios if your logic ever relies on chunk math.
5. getAllIds() Repeated Execution (CPU Overhead)
5.
getAllIds()
Repeated Execution (CPU Overhead)
The Risk:
If
getAllIds()
dynamically merges arrays (
array_merge(...$this->lists)
) every time it is invoked, and your ES processor calls this method inside a loop, it will spike CPU usage.
The Fix:
If the list is read frequently, the implementation should either cache the merged result and invalidate that cache when
addEntityList()
is called, or the caller should assign the result to a local variable before iterating.
Would you like me to draft an optimal, memory-efficient skeleton for the
SelectionList.php
implementation that avoids these specific pitfalls?
Good response
Bad response
Share & export
Copy
Show more options...
|
[{"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":"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 I’m on page “<tabTitle>JY-20808 low priority indexing queue by Vasil-Jimi</tabTitle>” with “<selection>@@ -5,84 +5,140 @@5namespace Tests\\Unit\\Component\\ES\\Processor\\DTOs;5namespace Tests\\Unit\\Component\\ES\\Processor\\DTOs;667use Jiminny\\Component\\ES\\Processor\\DTOs\\SelectionList;7use Jiminny\\Component\\ES\\Processor\\DTOs\\SelectionList;8+use Jiminny\\Component\\ES\\QueuePriorityEnum;8use PHPUnit\\Framework\\Attributes\\CoversClass;9use PHPUnit\\Framework\\Attributes\\CoversClass;9use PHPUnit\\Framework\\TestCase;10use PHPUnit\\Framework\\TestCase;101111#[CoversClass(SelectionList::class)]12#[CoversClass(SelectionList::class)]12final class SelectionListTest extends TestCase13final class SelectionListTest extends TestCase13{14{14-public function testGetEntityIds(): void15+private const int CHUNK_SIZE = 100;16+17+public function testAddEntityListAndGetAllIds(): void18+ {19+$selectionList = new SelectionList();20+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);21+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);22+23+$this->assertSame([1, 2, 3, 4], $selectionList->getAllIds());24+ }25+26+public function testAddEntityListMergesMultipleCallsForSamePriority(): void27+ {28+$selectionList = new SelectionList();29+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);30+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [3, 4]);31+32+$this->assertSame([1, 2, 3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));33+ }34+35+public function testGetEntityListItemsByGroup(): void36+ {37+$selectionList = new SelectionList();38+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);39+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);40+$selectionList->addEntityList(QueuePriorityEnum::LOW, [5, 6]);41+42+$this->assertSame([1, 2], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));43+$this->assertSame([3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::NORMAL));44+$this->assertSame([5, 6], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::LOW));45+ }46+47+public function testGetEntityListItemsByGroupReturnsEmptyArrayForUnknownGroup(): void15 {48 {16-$priority = ['p1', 'p2'];49+$selectionList = new SelectionList();17-$normal = ['n1', 'n2'];50+18-$selectionList = new SelectionList($priority, $normal);51+$this->assertSame([], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));52+ }195320-$this->assertSame($priority, $selectionList->getHighPriorityEntityIds());54+public function testGetEntityListGroups(): void21-$this->assertSame($normal, $selectionList->getNormalPriorityEntityId());55+ {56+$selectionList = new SelectionList();57+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);58+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2]);225923-$this->assertSame(['p1', 'p2', 'n1', 'n2'], $selectionList->getAllIds());60+$this->assertSame(['high', 'normal'], $selectionList->getEntityListGroups());24 }61 }256226public function testCountReturnsTotalCount(): void63public function testCountReturnsTotalCount(): void27 {64 {28-$selectionList = new SelectionList(['p1'], ['n1', 'n2']);65+$selectionList = new SelectionList();66+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);67+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2, 3]);68+29$this->assertSame(3, $selectionList->count());69$this->assertSame(3, $selectionList->count());30 }70 }317132-public function testIsEmptyReturnsTrueWhenBothListsAreEmpty(): void72+public function testIsEmptyReturnsTrueWhenNoEntitiesAdded(): void33 {73 {34-$selectionList = new SelectionList([], []);74+$selectionList = new SelectionList();75+35$this->assertTrue($selectionList->isEmpty());76$this->assertTrue($selectionList->isEmpty());36 }77 }377838-public function testIsEmptyReturnsFalseWhenAnyListIsNotEmpty(): void79+public function testIsEmptyReturnsFalseWhenEntitiesAdded(): void39 {80 {40-$selectionList = new SelectionList(['p1'], []);81+$selectionList = new SelectionList();41-$this->assertFalse($selectionList->isEmpty());82+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);428343-$selectionList2 = new SelectionList([], ['n1']);84+$this->assertFalse($selectionList->isEmpty());44-$this->assertFalse($selectionList2->isEmpty());45 }85 }468647-public function testIsStaleChunkSelected(): void87+public function testMarkStaleAndIsStaleChunkSelected(): void48 {88 {49-$selectionList = new SelectionList([], [], true);89+$selectionList = new SelectionList();50-$this->assertTrue($selectionList->isStaleChunkSelected());90+91+$this->assertFalse($selectionList->isStaleChunkSelected());92+93+$selectionList->markStale();519452-$selectionList2 = new SelectionList([], [], false);95+$this->assertTrue($selectionList->isStaleChunkSelected());53-$this->assertFalse($selectionList2->isStaleChunkSelected());54 }96 }559756public function testIsFullChunk(): void98public function testIsFullChunk(): void57 {99 {58-$chunkSize = 200;100+$selectionList = new SelectionList();59-101+$selectionList->setChunkSize(self::CHUNK_SIZE);60-$fullList = range(1, $chunkSize);102+61-$selectionList = new SelectionList(103+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, self::CHUNK_SIZE));62- priorityEntityIdList: $fullList,104+63- normalEntityIdList: [],105+$this->assertTrue($selectionList->isFullChunk());64- chunkSize: $chunkSize,106+ }65- );107+108+public function testIsNotFullChunkWhenBelowChunkSize(): void109+ {110+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);111+112+$selectionList = new SelectionList();113+$selectionList->setChunkSize(self::CHUNK_SIZE);114+115+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range(1, $halfRange));116+117+$this->assertFalse($selectionList->isFullChunk());118+ }119+120+public function testIsFullChunkAcrossMultiplePriorityGroups(): void121+ {122+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);123+124+$selectionList = new SelectionList();125+$selectionList->setChunkSize(self::CHUNK_SIZE);126+127+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, $halfRange));128+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range($halfRange + 1, self::CHUNK_SIZE));129+130+$this->assertTrue($selectionList->isFullChunk());131+ }132+133+public function testSetChunkSizeAffectsIsFullChunk(): void134+ {135+$selectionList = new SelectionList();136+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [1, 2, 3]);137+138+$selectionList->setChunkSize(3);66$this->assertTrue($selectionList->isFullChunk());139$this->assertTrue($selectionList->isFullChunk());6714068-$halfRange = (int) ceil($chunkSize / 2);141+$selectionList->setChunkSize(50);69-142+$this->assertFalse($selectionList->isFullChunk());70-$notFullList = range(1, $halfRange);71-$selectionList2 = new SelectionList(72- priorityEntityIdList: $notFullList,73- normalEntityIdList: [],74- chunkSize: $chunkSize,75- );76-$this->assertFalse($selectionList2->isFullChunk());77-78-$priorityRange = range(1, $halfRange);79-$normalRange = range($halfRange + 1, $chunkSize);80-81-$selectionList3 = new SelectionList(82- priorityEntityIdList: $priorityRange,83- normalEntityIdList: $normalRange,84- chunkSize: $chunkSize,85- );86-$this->assertTrue($selectionList3->isFullChunk());87 }143 }88}144}</selection>” selected. Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.","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":"I’m on page “<tabTitle>JY-20808 low priority indexing queue by Vasil-Jimi</tabTitle>” with “<selection>@@ -5,84 +5,140 @@5namespace Tests\\Unit\\Component\\ES\\Processor\\DTOs;5namespace Tests\\Unit\\Component\\ES\\Processor\\DTOs;667use Jiminny\\Component\\ES\\Processor\\DTOs\\SelectionList;7use Jiminny\\Component\\ES\\Processor\\DTOs\\SelectionList;8+use Jiminny\\Component\\ES\\QueuePriorityEnum;8use PHPUnit\\Framework\\Attributes\\CoversClass;9use PHPUnit\\Framework\\Attributes\\CoversClass;9use PHPUnit\\Framework\\TestCase;10use PHPUnit\\Framework\\TestCase;101111#[CoversClass(SelectionList::class)]12#[CoversClass(SelectionList::class)]12final class SelectionListTest extends TestCase13final class SelectionListTest extends TestCase13{14{14-public function testGetEntityIds(): void15+private const int CHUNK_SIZE = 100;16+17+public function testAddEntityListAndGetAllIds(): void18+ {19+$selectionList = new SelectionList();20+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);21+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);22+23+$this->assertSame([1, 2, 3, 4], $selectionList->getAllIds());24+ }25+26+public function testAddEntityListMergesMultipleCallsForSamePriority(): void27+ {28+$selectionList = new SelectionList();29+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);30+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [3, 4]);31+32+$this->assertSame([1, 2, 3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));33+ }34+35+public function testGetEntityListItemsByGroup(): void36+ {37+$selectionList = new SelectionList();38+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);39+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);40+$selectionList->addEntityList(QueuePriorityEnum::LOW, [5, 6]);41+42+$this->assertSame([1, 2], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));43+$this->assertSame([3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::NORMAL));44+$this->assertSame([5, 6], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::LOW));45+ }46+47+public function testGetEntityListItemsByGroupReturnsEmptyArrayForUnknownGroup(): void15 {48 {16-$priority = ['p1', 'p2'];49+$selectionList = new SelectionList();17-$normal = ['n1', 'n2'];50+18-$selectionList = new SelectionList($priority, $normal);51+$this->assertSame([], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));52+ }195320-$this->assertSame($priority, $selectionList->getHighPriorityEntityIds());54+public function testGetEntityListGroups(): void21-$this->assertSame($normal, $selectionList->getNormalPriorityEntityId());55+ {56+$selectionList = new SelectionList();57+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);58+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2]);225923-$this->assertSame(['p1', 'p2', 'n1', 'n2'], $selectionList->getAllIds());60+$this->assertSame(['high', 'normal'], $selectionList->getEntityListGroups());24 }61 }256226public function testCountReturnsTotalCount(): void63public function testCountReturnsTotalCount(): void27 {64 {28-$selectionList = new SelectionList(['p1'], ['n1', 'n2']);65+$selectionList = new SelectionList();66+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);67+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2, 3]);68+29$this->assertSame(3, $selectionList->count());69$this->assertSame(3, $selectionList->count());30 }70 }317132-public function testIsEmptyReturnsTrueWhenBothListsAreEmpty(): void72+public function testIsEmptyReturnsTrueWhenNoEntitiesAdded(): void33 {73 {34-$selectionList = new SelectionList([], []);74+$selectionList = new SelectionList();75+35$this->assertTrue($selectionList->isEmpty());76$this->assertTrue($selectionList->isEmpty());36 }77 }377838-public function testIsEmptyReturnsFalseWhenAnyListIsNotEmpty(): void79+public function testIsEmptyReturnsFalseWhenEntitiesAdded(): void39 {80 {40-$selectionList = new SelectionList(['p1'], []);81+$selectionList = new SelectionList();41-$this->assertFalse($selectionList->isEmpty());82+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);428343-$selectionList2 = new SelectionList([], ['n1']);84+$this->assertFalse($selectionList->isEmpty());44-$this->assertFalse($selectionList2->isEmpty());45 }85 }468647-public function testIsStaleChunkSelected(): void87+public function testMarkStaleAndIsStaleChunkSelected(): void48 {88 {49-$selectionList = new SelectionList([], [], true);89+$selectionList = new SelectionList();50-$this->assertTrue($selectionList->isStaleChunkSelected());90+91+$this->assertFalse($selectionList->isStaleChunkSelected());92+93+$selectionList->markStale();519452-$selectionList2 = new SelectionList([], [], false);95+$this->assertTrue($selectionList->isStaleChunkSelected());53-$this->assertFalse($selectionList2->isStaleChunkSelected());54 }96 }559756public function testIsFullChunk(): void98public function testIsFullChunk(): void57 {99 {58-$chunkSize = 200;100+$selectionList = new SelectionList();59-101+$selectionList->setChunkSize(self::CHUNK_SIZE);60-$fullList = range(1, $chunkSize);102+61-$selectionList = new SelectionList(103+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, self::CHUNK_SIZE));62- priorityEntityIdList: $fullList,104+63- normalEntityIdList: [],105+$this->assertTrue($selectionList->isFullChunk());64- chunkSize: $chunkSize,106+ }65- );107+108+public function testIsNotFullChunkWhenBelowChunkSize(): void109+ {110+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);111+112+$selectionList = new SelectionList();113+$selectionList->setChunkSize(self::CHUNK_SIZE);114+115+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range(1, $halfRange));116+117+$this->assertFalse($selectionList->isFullChunk());118+ }119+120+public function testIsFullChunkAcrossMultiplePriorityGroups(): void121+ {122+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);123+124+$selectionList = new SelectionList();125+$selectionList->setChunkSize(self::CHUNK_SIZE);126+127+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, $halfRange));128+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range($halfRange + 1, self::CHUNK_SIZE));129+130+$this->assertTrue($selectionList->isFullChunk());131+ }132+133+public function testSetChunkSizeAffectsIsFullChunk(): void134+ {135+$selectionList = new SelectionList();136+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [1, 2, 3]);137+138+$selectionList->setChunkSize(3);66$this->assertTrue($selectionList->isFullChunk());139$this->assertTrue($selectionList->isFullChunk());6714068-$halfRange = (int) ceil($chunkSize / 2);141+$selectionList->setChunkSize(50);69-142+$this->assertFalse($selectionList->isFullChunk());70-$notFullList = range(1, $halfRange);71-$selectionList2 = new SelectionList(72- priorityEntityIdList: $notFullList,73- normalEntityIdList: [],74- chunkSize: $chunkSize,75- );76-$this->assertFalse($selectionList2->isFullChunk());77-78-$priorityRange = range(1, $halfRange);79-$normalRange = range($halfRange + 1, $chunkSize);80-81-$selectionList3 = new SelectionList(82- priorityEntityIdList: $priorityRange,83- normalEntityIdList: $normalRange,84- chunkSize: $chunkSize,85- );86-$this->assertTrue($selectionList3->isFullChunk());87 }143 }88}144}</selection>” selected.","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Expand","depth":21,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"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":"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":"Here is a precise and concise summary of the code selection, which refactors","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SelectionListTest","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"to accommodate a shift from fixed high/normal priority properties to a more dynamic, enum-driven priority group architecture.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Refactored Priority Handling","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Refactored Priority Handling","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Dynamic Priority Groups:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Replaces fixed high/normal array parameters with the","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"QueuePriorityEnum","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"HIGH","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"NORMAL","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"LOW","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"), allowing entity lists to be managed dynamically by group types.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Merged Registrations:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Validates that multiple","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"addEntityList()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"calls targeting the same priority level properly merge their data instead of overwriting it.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Group Querying:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Tests new methods","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"getEntityListItemsByGroup()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"and","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"getEntityListGroups()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"to retrieve group-specific IDs or an array of active group names (e.g.,","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"['high', 'normal']","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":").","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Updated State and Count Validations","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Updated State and Count Validations","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Instantiation:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Tests now instantiate","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SelectionList","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"without initial constructor arguments, using setters and action methods instead.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Empty States:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Updates assertions (","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"isEmpty()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":") to verify state based on whether any entities have been dynamically added, rather than checking pre-defined constructor arrays.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Stale Flags:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Changes from passing a","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"stale","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"boolean via the constructor to explicitly triggering a mutable","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$selectionList->markStale()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"method.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Chunk Capacity Behavior","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Chunk Capacity Behavior","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Flexible Chunk Sizes:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Introduces a","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"setChunkSize()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"method, replacing the constructor-configured chunk boundary.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Capacity Assertions:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Retains and updates the logic for","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"isFullChunk()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":", ensuring it accurately evaluates capacity when elements span multiple dynamic priority groups or when the chunk limit is altered mid-lifecycle.","depth":26,"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":"AXHeading","text":"You said Are there any issues or potential bolltenecks","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":"Are there any issues or potential bolltenecks","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":"Based on the test diff you provided, we can infer a few potential issues and architectural bottlenecks in the underlying","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SelectionList","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"implementation. While the tests are well-structured, the behavior they describe hints at a few areas you might want to keep an eye on, particularly for an Elasticsearch (ES) processor queue.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Here are the potential issues and bottlenecks to consider:","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"1. Array Merging Overhead (Performance)","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1. Array Merging Overhead (Performance)","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"testAddEntityListMergesMultipleCallsForSamePriority","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"test shows that calling","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"addEntityList()","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"multiple times for the same priority group merges the arrays.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The Bottleneck:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"If the underlying implementation uses","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"array_merge()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"inside a loop to append these IDs, it creates a new array in memory every time it's called. If you are processing thousands of entities and appending them in small batches, this can lead to memory bloat and CPU degradation due to constant array reallocation.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Mitigation:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Ensure the implementation handles batch appends efficiently (e.g., using the spread operator","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"[...$existing, ...$new]","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"or appending via references) or groups the arrays before doing a single merge.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"2. Lack of Uniqueness/Deduplication (Logic)","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2. Lack of Uniqueness/Deduplication (Logic)","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"None of the tests explicitly verify what happens if duplicate IDs are added. For example, if you call","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"addEntityList(QueuePriorityEnum::HIGH, [1, 2])","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"and then","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"addEntityList(QueuePriorityEnum::HIGH, [2, 3])","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":".","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The Issue:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Does the getter return","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"[1, 2, 2, 3]","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"or","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"[1, 2, 3]","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"? If duplicates are not filtered out, your ES processor might end up indexing the same entity multiple times in a single chunk, which wastes I/O and processor cycles.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Mitigation:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The underlying class should ideally enforce uniqueness (e.g., using","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"array_unique()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"before resolving the chunk, or using ID keys as associative array keys to naturally prevent duplicates).","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"3. Memory Consumption with Large Chunks (Scalability)","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3. Memory Consumption with Large Chunks (Scalability)","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The tests introduce","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"setChunkSize()","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":". If this chunk size is configured to be very large (e.g., tens of thousands of IDs to bulk-send to Elasticsearch).","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The Bottleneck:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Holding massive arrays of IDs in memory across different priority groups can quickly hit PHP memory limits, especially if this","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SelectionList","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"object is kept alive during a long-running daemon or cron job.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Mitigation:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Monitor memory usage if","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"CHUNK_SIZE","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"grows, and ensure the","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SelectionList","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"object is properly destroyed (or garbage collected) after the chunk is processed to free up memory.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"4. Type Juggling","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"4. Type Juggling","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"In the original code, string IDs were used (","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"['p1', 'p2']","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"). In the refactored tests, integer IDs are used (","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"[1, 2]","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":").","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The Issue:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"If your system handles UUIDs (strings) vs. relational DB auto-increments (integers), make sure the underlying implementation uses strict comparisons (","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"===","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":") where necessary, especially if deduplicating arrays, to prevent PHP from juggling","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"'1'","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"and","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"improperly.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Would you like me to draft a quick test case to check how the class currently handles duplicate IDs, or is deduplication intentionally handled further down your pipeline?","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":"AXHeading","text":"You said what about non test files","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":"what about non test files","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":"Since we don't have the actual","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SelectionList.php","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"file, we have to reverse-engineer its implementation based on the test behaviors. Moving from a constructor-based, fixed-property model to a dynamic, mutable model introduces several potential pitfalls in the implementation file itself.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Here are the specific bottlenecks and issues to watch out for in the","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SelectionList.php","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"source code:","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"1. The count() Method Implementation (Performance Trap)","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1. The","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"count()","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Method Implementation (Performance Trap)","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The Risk:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"If","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"count()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"is implemented by calling","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$this->getAllIds()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"and counting the resulting merged array (e.g.,","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"return count($this->getAllIds());","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"), it will be highly inefficient. It would allocate a brand-new array in memory just to determine its length.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The Fix:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"count()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"should mathematically sum the sizes of the underlying group arrays without merging them:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"return array_sum(array_map('count', $this->entityLists));","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"2. Loss of Immutability (State Management)","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2. Loss of Immutability (State Management)","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The Risk:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The original code passed all data via the constructor, implying the DTO (Data Transfer Object) was immutable once created. The refactored version introduces mutability (","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"addEntityList()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"setChunkSize()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"markStale()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"). DTOs are typically passed between architectural layers; if one layer modifies the chunk size or adds entities while another is processing it, it can cause unpredictable side effects or race conditions in your queue processor.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The Fix:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Ensure that this object is not shared across asynchronous contexts, or consider returning cloned instances when mutating state if strict immutability is required.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"3. Enum Array Key Violations (PHP Quirks)","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3. Enum Array Key Violations (PHP Quirks)","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The Risk:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The tests show","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"QueuePriorityEnum::HIGH","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"being passed to methods. If the underlying code attempts to use this Enum directly as an array key (e.g.,","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$this->lists[$priority] = $ids;","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"), PHP will throw an error because objects (including Enums) cannot be used as standard array keys.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The Fix:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The implementation must map the Enum to its underlying scalar value (e.g.,","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$this->lists[$priority->value]","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":") or use PHP's","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"WeakMap","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"or","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SplObjectStorage","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":", though standard arrays using","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$priority->value","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"are much faster for simple lists.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"4. Uninitialized State Defaults (Logic Errors)","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"4. Uninitialized State Defaults (Logic Errors)","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The Risk:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The tests instantiate","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"new SelectionList()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"without arguments, then later call","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$selectionList->setChunkSize(100)","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":". If","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"isFullChunk()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"is called","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"before","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"setChunkSize()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"is invoked, what happens?","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The Fix:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Ensure","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SelectionList","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"has a sensible default for chunk size (e.g.,","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private int $chunkSize = 0;","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"or a system default) to prevent uninitialized property errors or division-by-zero scenarios if your logic ever relies on chunk math.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"5. getAllIds() Repeated Execution (CPU Overhead)","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"5.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"getAllIds()","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Repeated Execution (CPU Overhead)","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The Risk:","depth":26,"bounds":{"left":0.12599733,"top":0.0,"width":0.023603724,"height":0.016360734},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"If","depth":26,"bounds":{"left":0.14960106,"top":0.0,"width":0.005984043,"height":0.016360734},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"getAllIds()","depth":27,"bounds":{"left":0.1575798,"top":0.0,"width":0.030751329,"height":0.014764565},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"dynamically merges arrays (","depth":26,"bounds":{"left":0.1903258,"top":0.0,"width":0.06898271,"height":0.016360734},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"array_merge(...$this->lists)","depth":27,"bounds":{"left":0.2613032,"top":0.0,"width":0.078125,"height":0.014764565},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":") every time it is invoked, and your ES processor calls this method inside a loop, it will spike CPU usage.","depth":26,"bounds":{"left":0.12599733,"top":0.0,"width":0.23271276,"height":0.038707104},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The Fix:","depth":26,"bounds":{"left":0.12599733,"top":0.0,"width":0.020279255,"height":0.016360734},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"If the list is read frequently, the implementation should either cache the merged result and invalidate that cache when","depth":26,"bounds":{"left":0.12599733,"top":0.0,"width":0.23005319,"height":0.038707104},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"addEntityList()","depth":27,"bounds":{"left":0.2044548,"top":0.002793296,"width":0.041888297,"height":0.014764565},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"is called, or the caller should assign the result to a local variable before iterating.","depth":26,"bounds":{"left":0.12599733,"top":0.0015961692,"width":0.2200798,"height":0.038707104},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Would you like me to draft an optimal, memory-efficient skeleton for the","depth":24,"bounds":{"left":0.11336436,"top":0.06624102,"width":0.1747008,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SelectionList.php","depth":25,"bounds":{"left":0.29005983,"top":0.06743815,"width":0.04737367,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"implementation that avoids these specific pitfalls?","depth":24,"bounds":{"left":0.11336436,"top":0.06624102,"width":0.22739361,"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}]...
|
38523222066746791
|
5896451135607762965
|
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
Copy prompt
You said I’m on page “<tabTitle>JY-20808 low priority indexing queue by Vasil-Jimi</tabTitle>” with “<selection>@@ -5,84 +5,140 @@5namespace Tests\Unit\Component\ES\Processor\DTOs;5namespace Tests\Unit\Component\ES\Processor\DTOs;667use Jiminny\Component\ES\Processor\DTOs\SelectionList;7use Jiminny\Component\ES\Processor\DTOs\SelectionList;8+use Jiminny\Component\ES\QueuePriorityEnum;8use PHPUnit\Framework\Attributes\CoversClass;9use PHPUnit\Framework\Attributes\CoversClass;9use PHPUnit\Framework\TestCase;10use PHPUnit\Framework\TestCase;101111#[CoversClass(SelectionList::class)]12#[CoversClass(SelectionList::class)]12final class SelectionListTest extends TestCase13final class SelectionListTest extends TestCase13{14{14-public function testGetEntityIds(): void15+private const int CHUNK_SIZE = 100;16+17+public function testAddEntityListAndGetAllIds(): void18+ {19+$selectionList = new SelectionList();20+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);21+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);22+23+$this->assertSame([1, 2, 3, 4], $selectionList->getAllIds());24+ }25+26+public function testAddEntityListMergesMultipleCallsForSamePriority(): void27+ {28+$selectionList = new SelectionList();29+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);30+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [3, 4]);31+32+$this->assertSame([1, 2, 3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));33+ }34+35+public function testGetEntityListItemsByGroup(): void36+ {37+$selectionList = new SelectionList();38+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);39+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);40+$selectionList->addEntityList(QueuePriorityEnum::LOW, [5, 6]);41+42+$this->assertSame([1, 2], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));43+$this->assertSame([3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::NORMAL));44+$this->assertSame([5, 6], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::LOW));45+ }46+47+public function testGetEntityListItemsByGroupReturnsEmptyArrayForUnknownGroup(): void15 {48 {16-$priority = ['p1', 'p2'];49+$selectionList = new SelectionList();17-$normal = ['n1', 'n2'];50+18-$selectionList = new SelectionList($priority, $normal);51+$this->assertSame([], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));52+ }195320-$this->assertSame($priority, $selectionList->getHighPriorityEntityIds());54+public function testGetEntityListGroups(): void21-$this->assertSame($normal, $selectionList->getNormalPriorityEntityId());55+ {56+$selectionList = new SelectionList();57+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);58+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2]);225923-$this->assertSame(['p1', 'p2', 'n1', 'n2'], $selectionList->getAllIds());60+$this->assertSame(['high', 'normal'], $selectionList->getEntityListGroups());24 }61 }256226public function testCountReturnsTotalCount(): void63public function testCountReturnsTotalCount(): void27 {64 {28-$selectionList = new SelectionList(['p1'], ['n1', 'n2']);65+$selectionList = new SelectionList();66+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);67+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2, 3]);68+29$this->assertSame(3, $selectionList->count());69$this->assertSame(3, $selectionList->count());30 }70 }317132-public function testIsEmptyReturnsTrueWhenBothListsAreEmpty(): void72+public function testIsEmptyReturnsTrueWhenNoEntitiesAdded(): void33 {73 {34-$selectionList = new SelectionList([], []);74+$selectionList = new SelectionList();75+35$this->assertTrue($selectionList->isEmpty());76$this->assertTrue($selectionList->isEmpty());36 }77 }377838-public function testIsEmptyReturnsFalseWhenAnyListIsNotEmpty(): void79+public function testIsEmptyReturnsFalseWhenEntitiesAdded(): void39 {80 {40-$selectionList = new SelectionList(['p1'], []);81+$selectionList = new SelectionList();41-$this->assertFalse($selectionList->isEmpty());82+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);428343-$selectionList2 = new SelectionList([], ['n1']);84+$this->assertFalse($selectionList->isEmpty());44-$this->assertFalse($selectionList2->isEmpty());45 }85 }468647-public function testIsStaleChunkSelected(): void87+public function testMarkStaleAndIsStaleChunkSelected(): void48 {88 {49-$selectionList = new SelectionList([], [], true);89+$selectionList = new SelectionList();50-$this->assertTrue($selectionList->isStaleChunkSelected());90+91+$this->assertFalse($selectionList->isStaleChunkSelected());92+93+$selectionList->markStale();519452-$selectionList2 = new SelectionList([], [], false);95+$this->assertTrue($selectionList->isStaleChunkSelected());53-$this->assertFalse($selectionList2->isStaleChunkSelected());54 }96 }559756public function testIsFullChunk(): void98public function testIsFullChunk(): void57 {99 {58-$chunkSize = 200;100+$selectionList = new SelectionList();59-101+$selectionList->setChunkSize(self::CHUNK_SIZE);60-$fullList = range(1, $chunkSize);102+61-$selectionList = new SelectionList(103+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, self::CHUNK_SIZE));62- priorityEntityIdList: $fullList,104+63- normalEntityIdList: [],105+$this->assertTrue($selectionList->isFullChunk());64- chunkSize: $chunkSize,106+ }65- );107+108+public function testIsNotFullChunkWhenBelowChunkSize(): void109+ {110+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);111+112+$selectionList = new SelectionList();113+$selectionList->setChunkSize(self::CHUNK_SIZE);114+115+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range(1, $halfRange));116+117+$this->assertFalse($selectionList->isFullChunk());118+ }119+120+public function testIsFullChunkAcrossMultiplePriorityGroups(): void121+ {122+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);123+124+$selectionList = new SelectionList();125+$selectionList->setChunkSize(self::CHUNK_SIZE);126+127+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, $halfRange));128+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range($halfRange + 1, self::CHUNK_SIZE));129+130+$this->assertTrue($selectionList->isFullChunk());131+ }132+133+public function testSetChunkSizeAffectsIsFullChunk(): void134+ {135+$selectionList = new SelectionList();136+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [1, 2, 3]);137+138+$selectionList->setChunkSize(3);66$this->assertTrue($selectionList->isFullChunk());139$this->assertTrue($selectionList->isFullChunk());6714068-$halfRange = (int) ceil($chunkSize / 2);141+$selectionList->setChunkSize(50);69-142+$this->assertFalse($selectionList->isFullChunk());70-$notFullList = range(1, $halfRange);71-$selectionList2 = new SelectionList(72- priorityEntityIdList: $notFullList,73- normalEntityIdList: [],74- chunkSize: $chunkSize,75- );76-$this->assertFalse($selectionList2->isFullChunk());77-78-$priorityRange = range(1, $halfRange);79-$normalRange = range($halfRange + 1, $chunkSize);80-81-$selectionList3 = new SelectionList(82- priorityEntityIdList: $priorityRange,83- normalEntityIdList: $normalRange,84- chunkSize: $chunkSize,85- );86-$this->assertTrue($selectionList3->isFullChunk());87 }143 }88}144}</selection>” selected. Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
You said
I’m on page “<tabTitle>JY-20808 low priority indexing queue by Vasil-Jimi</tabTitle>” with “<selection>@@ -5,84 +5,140 @@5namespace Tests\Unit\Component\ES\Processor\DTOs;5namespace Tests\Unit\Component\ES\Processor\DTOs;667use Jiminny\Component\ES\Processor\DTOs\SelectionList;7use Jiminny\Component\ES\Processor\DTOs\SelectionList;8+use Jiminny\Component\ES\QueuePriorityEnum;8use PHPUnit\Framework\Attributes\CoversClass;9use PHPUnit\Framework\Attributes\CoversClass;9use PHPUnit\Framework\TestCase;10use PHPUnit\Framework\TestCase;101111#[CoversClass(SelectionList::class)]12#[CoversClass(SelectionList::class)]12final class SelectionListTest extends TestCase13final class SelectionListTest extends TestCase13{14{14-public function testGetEntityIds(): void15+private const int CHUNK_SIZE = 100;16+17+public function testAddEntityListAndGetAllIds(): void18+ {19+$selectionList = new SelectionList();20+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);21+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);22+23+$this->assertSame([1, 2, 3, 4], $selectionList->getAllIds());24+ }25+26+public function testAddEntityListMergesMultipleCallsForSamePriority(): void27+ {28+$selectionList = new SelectionList();29+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);30+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [3, 4]);31+32+$this->assertSame([1, 2, 3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));33+ }34+35+public function testGetEntityListItemsByGroup(): void36+ {37+$selectionList = new SelectionList();38+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);39+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);40+$selectionList->addEntityList(QueuePriorityEnum::LOW, [5, 6]);41+42+$this->assertSame([1, 2], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));43+$this->assertSame([3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::NORMAL));44+$this->assertSame([5, 6], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::LOW));45+ }46+47+public function testGetEntityListItemsByGroupReturnsEmptyArrayForUnknownGroup(): void15 {48 {16-$priority = ['p1', 'p2'];49+$selectionList = new SelectionList();17-$normal = ['n1', 'n2'];50+18-$selectionList = new SelectionList($priority, $normal);51+$this->assertSame([], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));52+ }195320-$this->assertSame($priority, $selectionList->getHighPriorityEntityIds());54+public function testGetEntityListGroups(): void21-$this->assertSame($normal, $selectionList->getNormalPriorityEntityId());55+ {56+$selectionList = new SelectionList();57+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);58+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2]);225923-$this->assertSame(['p1', 'p2', 'n1', 'n2'], $selectionList->getAllIds());60+$this->assertSame(['high', 'normal'], $selectionList->getEntityListGroups());24 }61 }256226public function testCountReturnsTotalCount(): void63public function testCountReturnsTotalCount(): void27 {64 {28-$selectionList = new SelectionList(['p1'], ['n1', 'n2']);65+$selectionList = new SelectionList();66+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);67+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2, 3]);68+29$this->assertSame(3, $selectionList->count());69$this->assertSame(3, $selectionList->count());30 }70 }317132-public function testIsEmptyReturnsTrueWhenBothListsAreEmpty(): void72+public function testIsEmptyReturnsTrueWhenNoEntitiesAdded(): void33 {73 {34-$selectionList = new SelectionList([], []);74+$selectionList = new SelectionList();75+35$this->assertTrue($selectionList->isEmpty());76$this->assertTrue($selectionList->isEmpty());36 }77 }377838-public function testIsEmptyReturnsFalseWhenAnyListIsNotEmpty(): void79+public function testIsEmptyReturnsFalseWhenEntitiesAdded(): void39 {80 {40-$selectionList = new SelectionList(['p1'], []);81+$selectionList = new SelectionList();41-$this->assertFalse($selectionList->isEmpty());82+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);428343-$selectionList2 = new SelectionList([], ['n1']);84+$this->assertFalse($selectionList->isEmpty());44-$this->assertFalse($selectionList2->isEmpty());45 }85 }468647-public function testIsStaleChunkSelected(): void87+public function testMarkStaleAndIsStaleChunkSelected(): void48 {88 {49-$selectionList = new SelectionList([], [], true);89+$selectionList = new SelectionList();50-$this->assertTrue($selectionList->isStaleChunkSelected());90+91+$this->assertFalse($selectionList->isStaleChunkSelected());92+93+$selectionList->markStale();519452-$selectionList2 = new SelectionList([], [], false);95+$this->assertTrue($selectionList->isStaleChunkSelected());53-$this->assertFalse($selectionList2->isStaleChunkSelected());54 }96 }559756public function testIsFullChunk(): void98public function testIsFullChunk(): void57 {99 {58-$chunkSize = 200;100+$selectionList = new SelectionList();59-101+$selectionList->setChunkSize(self::CHUNK_SIZE);60-$fullList = range(1, $chunkSize);102+61-$selectionList = new SelectionList(103+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, self::CHUNK_SIZE));62- priorityEntityIdList: $fullList,104+63- normalEntityIdList: [],105+$this->assertTrue($selectionList->isFullChunk());64- chunkSize: $chunkSize,106+ }65- );107+108+public function testIsNotFullChunkWhenBelowChunkSize(): void109+ {110+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);111+112+$selectionList = new SelectionList();113+$selectionList->setChunkSize(self::CHUNK_SIZE);114+115+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range(1, $halfRange));116+117+$this->assertFalse($selectionList->isFullChunk());118+ }119+120+public function testIsFullChunkAcrossMultiplePriorityGroups(): void121+ {122+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);123+124+$selectionList = new SelectionList();125+$selectionList->setChunkSize(self::CHUNK_SIZE);126+127+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, $halfRange));128+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range($halfRange + 1, self::CHUNK_SIZE));129+130+$this->assertTrue($selectionList->isFullChunk());131+ }132+133+public function testSetChunkSizeAffectsIsFullChunk(): void134+ {135+$selectionList = new SelectionList();136+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [1, 2, 3]);137+138+$selectionList->setChunkSize(3);66$this->assertTrue($selectionList->isFullChunk());139$this->assertTrue($selectionList->isFullChunk());6714068-$halfRange = (int) ceil($chunkSize / 2);141+$selectionList->setChunkSize(50);69-142+$this->assertFalse($selectionList->isFullChunk());70-$notFullList = range(1, $halfRange);71-$selectionList2 = new SelectionList(72- priorityEntityIdList: $notFullList,73- normalEntityIdList: [],74- chunkSize: $chunkSize,75- );76-$this->assertFalse($selectionList2->isFullChunk());77-78-$priorityRange = range(1, $halfRange);79-$normalRange = range($halfRange + 1, $chunkSize);80-81-$selectionList3 = new SelectionList(82- priorityEntityIdList: $priorityRange,83- normalEntityIdList: $normalRange,84- chunkSize: $chunkSize,85- );86-$this->assertTrue($selectionList3->isFullChunk());87 }143 }88}144}</selection>” selected.
Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
Expand
Listen
Gemini said
Gemini said
Here is a precise and concise summary of the code selection, which refactors
SelectionListTest
to accommodate a shift from fixed high/normal priority properties to a more dynamic, enum-driven priority group architecture.
Refactored Priority Handling
Refactored Priority Handling
Dynamic Priority Groups:
Replaces fixed high/normal array parameters with the
QueuePriorityEnum
(
HIGH
,
NORMAL
,
LOW
), allowing entity lists to be managed dynamically by group types.
Merged Registrations:
Validates that multiple
addEntityList()
calls targeting the same priority level properly merge their data instead of overwriting it.
Group Querying:
Tests new methods
getEntityListItemsByGroup()
and
getEntityListGroups()
to retrieve group-specific IDs or an array of active group names (e.g.,
['high', 'normal']
).
Updated State and Count Validations
Updated State and Count Validations
Instantiation:
Tests now instantiate
SelectionList
without initial constructor arguments, using setters and action methods instead.
Empty States:
Updates assertions (
isEmpty()
) to verify state based on whether any entities have been dynamically added, rather than checking pre-defined constructor arrays.
Stale Flags:
Changes from passing a
stale
boolean via the constructor to explicitly triggering a mutable
$selectionList->markStale()
method.
Chunk Capacity Behavior
Chunk Capacity Behavior
Flexible Chunk Sizes:
Introduces a
setChunkSize()
method, replacing the constructor-configured chunk boundary.
Capacity Assertions:
Retains and updates the logic for
isFullChunk()
, ensuring it accurately evaluates capacity when elements span multiple dynamic priority groups or when the chunk limit is altered mid-lifecycle.
Good response
Bad response
Share & export
Copy
Show more options
Copy prompt
You said Are there any issues or potential bolltenecks
You said
Are there any issues or potential bolltenecks
Listen
Show thinking
Gemini said
Gemini said
Based on the test diff you provided, we can infer a few potential issues and architectural bottlenecks in the underlying
SelectionList
implementation. While the tests are well-structured, the behavior they describe hints at a few areas you might want to keep an eye on, particularly for an Elasticsearch (ES) processor queue.
Here are the potential issues and bottlenecks to consider:
1. Array Merging Overhead (Performance)
1. Array Merging Overhead (Performance)
The
testAddEntityListMergesMultipleCallsForSamePriority
test shows that calling
addEntityList()
multiple times for the same priority group merges the arrays.
The Bottleneck:
If the underlying implementation uses
array_merge()
inside a loop to append these IDs, it creates a new array in memory every time it's called. If you are processing thousands of entities and appending them in small batches, this can lead to memory bloat and CPU degradation due to constant array reallocation.
Mitigation:
Ensure the implementation handles batch appends efficiently (e.g., using the spread operator
[...$existing, ...$new]
or appending via references) or groups the arrays before doing a single merge.
2. Lack of Uniqueness/Deduplication (Logic)
2. Lack of Uniqueness/Deduplication (Logic)
None of the tests explicitly verify what happens if duplicate IDs are added. For example, if you call
addEntityList(QueuePriorityEnum::HIGH, [1, 2])
and then
addEntityList(QueuePriorityEnum::HIGH, [2, 3])
.
The Issue:
Does the getter return
[1, 2, 2, 3]
or
[1, 2, 3]
? If duplicates are not filtered out, your ES processor might end up indexing the same entity multiple times in a single chunk, which wastes I/O and processor cycles.
Mitigation:
The underlying class should ideally enforce uniqueness (e.g., using
array_unique()
before resolving the chunk, or using ID keys as associative array keys to naturally prevent duplicates).
3. Memory Consumption with Large Chunks (Scalability)
3. Memory Consumption with Large Chunks (Scalability)
The tests introduce
setChunkSize()
. If this chunk size is configured to be very large (e.g., tens of thousands of IDs to bulk-send to Elasticsearch).
The Bottleneck:
Holding massive arrays of IDs in memory across different priority groups can quickly hit PHP memory limits, especially if this
SelectionList
object is kept alive during a long-running daemon or cron job.
Mitigation:
Monitor memory usage if
CHUNK_SIZE
grows, and ensure the
SelectionList
object is properly destroyed (or garbage collected) after the chunk is processed to free up memory.
4. Type Juggling
4. Type Juggling
In the original code, string IDs were used (
['p1', 'p2']
). In the refactored tests, integer IDs are used (
[1, 2]
).
The Issue:
If your system handles UUIDs (strings) vs. relational DB auto-increments (integers), make sure the underlying implementation uses strict comparisons (
===
) where necessary, especially if deduplicating arrays, to prevent PHP from juggling
'1'
and
1
improperly.
Would you like me to draft a quick test case to check how the class currently handles duplicate IDs, or is deduplication intentionally handled further down your pipeline?
Good response
Bad response
Share & export
Copy
Show more options
Copy prompt
You said what about non test files
You said
what about non test files
Listen
Show thinking
Gemini said
Gemini said
Since we don't have the actual
SelectionList.php
file, we have to reverse-engineer its implementation based on the test behaviors. Moving from a constructor-based, fixed-property model to a dynamic, mutable model introduces several potential pitfalls in the implementation file itself.
Here are the specific bottlenecks and issues to watch out for in the
SelectionList.php
source code:
1. The count() Method Implementation (Performance Trap)
1. The
count()
Method Implementation (Performance Trap)
The Risk:
If
count()
is implemented by calling
$this->getAllIds()
and counting the resulting merged array (e.g.,
return count($this->getAllIds());
), it will be highly inefficient. It would allocate a brand-new array in memory just to determine its length.
The Fix:
count()
should mathematically sum the sizes of the underlying group arrays without merging them:
return array_sum(array_map('count', $this->entityLists));
2. Loss of Immutability (State Management)
2. Loss of Immutability (State Management)
The Risk:
The original code passed all data via the constructor, implying the DTO (Data Transfer Object) was immutable once created. The refactored version introduces mutability (
addEntityList()
,
setChunkSize()
,
markStale()
). DTOs are typically passed between architectural layers; if one layer modifies the chunk size or adds entities while another is processing it, it can cause unpredictable side effects or race conditions in your queue processor.
The Fix:
Ensure that this object is not shared across asynchronous contexts, or consider returning cloned instances when mutating state if strict immutability is required.
3. Enum Array Key Violations (PHP Quirks)
3. Enum Array Key Violations (PHP Quirks)
The Risk:
The tests show
QueuePriorityEnum::HIGH
being passed to methods. If the underlying code attempts to use this Enum directly as an array key (e.g.,
$this->lists[$priority] = $ids;
), PHP will throw an error because objects (including Enums) cannot be used as standard array keys.
The Fix:
The implementation must map the Enum to its underlying scalar value (e.g.,
$this->lists[$priority->value]
) or use PHP's
WeakMap
or
SplObjectStorage
, though standard arrays using
$priority->value
are much faster for simple lists.
4. Uninitialized State Defaults (Logic Errors)
4. Uninitialized State Defaults (Logic Errors)
The Risk:
The tests instantiate
new SelectionList()
without arguments, then later call
$selectionList->setChunkSize(100)
. If
isFullChunk()
is called
before
setChunkSize()
is invoked, what happens?
The Fix:
Ensure
SelectionList
has a sensible default for chunk size (e.g.,
private int $chunkSize = 0;
or a system default) to prevent uninitialized property errors or division-by-zero scenarios if your logic ever relies on chunk math.
5. getAllIds() Repeated Execution (CPU Overhead)
5.
getAllIds()
Repeated Execution (CPU Overhead)
The Risk:
If
getAllIds()
dynamically merges arrays (
array_merge(...$this->lists)
) every time it is invoked, and your ES processor calls this method inside a loop, it will spike CPU usage.
The Fix:
If the list is read frequently, the implementation should either cache the merged result and invalidate that cache when
addEntityList()
is called, or the caller should assign the result to a local variable before iterating.
Would you like me to draft an optimal, memory-efficient skeleton for the
SelectionList.php
implementation that avoids these specific pitfalls?
Good response
Bad response
Share & export
Copy
Show more options...
|
55654
|
NULL
|
NULL
|
NULL
|
|
55656
|
1930
|
12
|
2026-05-19T06:35:44.430452+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779172544430_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-4bd github.com/jiminny/app/pull/12082/changes#diff-4bdd02759b5e0d060dcbc8c2dcb9bdbc3d0266d9c2e29956b9d63916dae1fdd7...
|
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
Copy prompt
You said I’m on page “<tabTitle>JY-20808 low priority indexing queue by Vasil-Jimi</tabTitle>” with “<selection>@@ -5,84 +5,140 @@5namespace Tests\Unit\Component\ES\Processor\DTOs;5namespace Tests\Unit\Component\ES\Processor\DTOs;667use Jiminny\Component\ES\Processor\DTOs\SelectionList;7use Jiminny\Component\ES\Processor\DTOs\SelectionList;8+use Jiminny\Component\ES\QueuePriorityEnum;8use PHPUnit\Framework\Attributes\CoversClass;9use PHPUnit\Framework\Attributes\CoversClass;9use PHPUnit\Framework\TestCase;10use PHPUnit\Framework\TestCase;101111#[CoversClass(SelectionList::class)]12#[CoversClass(SelectionList::class)]12final class SelectionListTest extends TestCase13final class SelectionListTest extends TestCase13{14{14-public function testGetEntityIds(): void15+private const int CHUNK_SIZE = 100;16+17+public function testAddEntityListAndGetAllIds(): void18+ {19+$selectionList = new SelectionList();20+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);21+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);22+23+$this->assertSame([1, 2, 3, 4], $selectionList->getAllIds());24+ }25+26+public function testAddEntityListMergesMultipleCallsForSamePriority(): void27+ {28+$selectionList = new SelectionList();29+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);30+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [3, 4]);31+32+$this->assertSame([1, 2, 3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));33+ }34+35+public function testGetEntityListItemsByGroup(): void36+ {37+$selectionList = new SelectionList();38+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);39+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);40+$selectionList->addEntityList(QueuePriorityEnum::LOW, [5, 6]);41+42+$this->assertSame([1, 2], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));43+$this->assertSame([3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::NORMAL));44+$this->assertSame([5, 6], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::LOW));45+ }46+47+public function testGetEntityListItemsByGroupReturnsEmptyArrayForUnknownGroup(): void15 {48 {16-$priority = ['p1', 'p2'];49+$selectionList = new SelectionList();17-$normal = ['n1', 'n2'];50+18-$selectionList = new SelectionList($priority, $normal);51+$this->assertSame([], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));52+ }195320-$this->assertSame($priority, $selectionList->getHighPriorityEntityIds());54+public function testGetEntityListGroups(): void21-$this->assertSame($normal, $selectionList->getNormalPriorityEntityId());55+ {56+$selectionList = new SelectionList();57+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);58+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2]);225923-$this->assertSame(['p1', 'p2', 'n1', 'n2'], $selectionList->getAllIds());60+$this->assertSame(['high', 'normal'], $selectionList->getEntityListGroups());24 }61 }256226public function testCountReturnsTotalCount(): void63public function testCountReturnsTotalCount(): void27 {64 {28-$selectionList = new SelectionList(['p1'], ['n1', 'n2']);65+$selectionList = new SelectionList();66+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);67+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2, 3]);68+29$this->assertSame(3, $selectionList->count());69$this->assertSame(3, $selectionList->count());30 }70 }317132-public function testIsEmptyReturnsTrueWhenBothListsAreEmpty(): void72+public function testIsEmptyReturnsTrueWhenNoEntitiesAdded(): void33 {73 {34-$selectionList = new SelectionList([], []);74+$selectionList = new SelectionList();75+35$this->assertTrue($selectionList->isEmpty());76$this->assertTrue($selectionList->isEmpty());36 }77 }377838-public function testIsEmptyReturnsFalseWhenAnyListIsNotEmpty(): void79+public function testIsEmptyReturnsFalseWhenEntitiesAdded(): void39 {80 {40-$selectionList = new SelectionList(['p1'], []);81+$selectionList = new SelectionList();41-$this->assertFalse($selectionList->isEmpty());82+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);428343-$selectionList2 = new SelectionList([], ['n1']);84+$this->assertFalse($selectionList->isEmpty());44-$this->assertFalse($selectionList2->isEmpty());45 }85 }468647-public function testIsStaleChunkSelected(): void87+public function testMarkStaleAndIsStaleChunkSelected(): void48 {88 {49-$selectionList = new SelectionList([], [], true);89+$selectionList = new SelectionList();50-$this->assertTrue($selectionList->isStaleChunkSelected());90+91+$this->assertFalse($selectionList->isStaleChunkSelected());92+93+$selectionList->markStale();519452-$selectionList2 = new SelectionList([], [], false);95+$this->assertTrue($selectionList->isStaleChunkSelected());53-$this->assertFalse($selectionList2->isStaleChunkSelected());54 }96 }559756public function testIsFullChunk(): void98public function testIsFullChunk(): void57 {99 {58-$chunkSize = 200;100+$selectionList = new SelectionList();59-101+$selectionList->setChunkSize(self::CHUNK_SIZE);60-$fullList = range(1, $chunkSize);102+61-$selectionList = new SelectionList(103+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, self::CHUNK_SIZE));62- priorityEntityIdList: $fullList,104+63- normalEntityIdList: [],105+$this->assertTrue($selectionList->isFullChunk());64- chunkSize: $chunkSize,106+ }65- );107+108+public function testIsNotFullChunkWhenBelowChunkSize(): void109+ {110+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);111+112+$selectionList = new SelectionList();113+$selectionList->setChunkSize(self::CHUNK_SIZE);114+115+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range(1, $halfRange));116+117+$this->assertFalse($selectionList->isFullChunk());118+ }119+120+public function testIsFullChunkAcrossMultiplePriorityGroups(): void121+ {122+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);123+124+$selectionList = new SelectionList();125+$selectionList->setChunkSize(self::CHUNK_SIZE);126+127+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, $halfRange));128+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range($halfRange + 1, self::CHUNK_SIZE));129+130+$this->assertTrue($selectionList->isFullChunk());131+ }132+133+public function testSetChunkSizeAffectsIsFullChunk(): void134+ {135+$selectionList = new SelectionList();136+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [1, 2, 3]);137+138+$selectionList->setChunkSize(3);66$this->assertTrue($selectionList->isFullChunk());139$this->assertTrue($selectionList->isFullChunk());6714068-$halfRange = (int) ceil($chunkSize / 2);141+$selectionList->setChunkSize(50);69-142+$this->assertFalse($selectionList->isFullChunk());70-$notFullList = range(1, $halfRange);71-$selectionList2 = new SelectionList(72- priorityEntityIdList: $notFullList,73- normalEntityIdList: [],74- chunkSize: $chunkSize,75- );76-$this->assertFalse($selectionList2->isFullChunk());77-78-$priorityRange = range(1, $halfRange);79-$normalRange = range($halfRange + 1, $chunkSize);80-81-$selectionList3 = new SelectionList(82- priorityEntityIdList: $priorityRange,83- normalEntityIdList: $normalRange,84- chunkSize: $chunkSize,85- );86-$this->assertTrue($selectionList3->isFullChunk());87 }143 }88}144}</selection>” selected. Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
You said
I’m on page “<tabTitle>JY-20808 low priority indexing queue by Vasil-Jimi</tabTitle>” with “<selection>@@ -5,84 +5,140 @@5namespace Tests\Unit\Component\ES\Processor\DTOs;5namespace Tests\Unit\Component\ES\Processor\DTOs;667use Jiminny\Component\ES\Processor\DTOs\SelectionList;7use Jiminny\Component\ES\Processor\DTOs\SelectionList;8+use Jiminny\Component\ES\QueuePriorityEnum;8use PHPUnit\Framework\Attributes\CoversClass;9use PHPUnit\Framework\Attributes\CoversClass;9use PHPUnit\Framework\TestCase;10use PHPUnit\Framework\TestCase;101111#[CoversClass(SelectionList::class)]12#[CoversClass(SelectionList::class)]12final class SelectionListTest extends TestCase13final class SelectionListTest extends TestCase13{14{14-public function testGetEntityIds(): void15+private const int CHUNK_SIZE = 100;16+17+public function testAddEntityListAndGetAllIds(): void18+ {19+$selectionList = new SelectionList();20+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);21+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);22+23+$this->assertSame([1, 2, 3, 4], $selectionList->getAllIds());24+ }25+26+public function testAddEntityListMergesMultipleCallsForSamePriority(): void27+ {28+$selectionList = new SelectionList();29+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);30+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [3, 4]);31+32+$this->assertSame([1, 2, 3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));33+ }34+35+public function testGetEntityListItemsByGroup(): void36+ {37+$selectionList = new SelectionList();38+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);39+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);40+$selectionList->addEntityList(QueuePriorityEnum::LOW, [5, 6]);41+42+$this->assertSame([1, 2], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));43+$this->assertSame([3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::NORMAL));44+$this->assertSame([5, 6], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::LOW));45+ }46+47+public function testGetEntityListItemsByGroupReturnsEmptyArrayForUnknownGroup(): void15 {48 {16-$priority = ['p1', 'p2'];49+$selectionList = new SelectionList();17-$normal = ['n1', 'n2'];50+18-$selectionList = new SelectionList($priority, $normal);51+$this->assertSame([], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));52+ }195320-$this->assertSame($priority, $selectionList->getHighPriorityEntityIds());54+public function testGetEntityListGroups(): void21-$this->assertSame($normal, $selectionList->getNormalPriorityEntityId());55+ {56+$selectionList = new SelectionList();57+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);58+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2]);225923-$this->assertSame(['p1', 'p2', 'n1', 'n2'], $selectionList->getAllIds());60+$this->assertSame(['high', 'normal'], $selectionList->getEntityListGroups());24 }61 }256226public function testCountReturnsTotalCount(): void63public function testCountReturnsTotalCount(): void27 {64 {28-$selectionList = new SelectionList(['p1'], ['n1', 'n2']);65+$selectionList = new SelectionList();66+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);67+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2, 3]);68+29$this->assertSame(3, $selectionList->count());69$this->assertSame(3, $selectionList->count());30 }70 }317132-public function testIsEmptyReturnsTrueWhenBothListsAreEmpty(): void72+public function testIsEmptyReturnsTrueWhenNoEntitiesAdded(): void33 {73 {34-$selectionList = new SelectionList([], []);74+$selectionList = new SelectionList();75+35$this->assertTrue($selectionList->isEmpty());76$this->assertTrue($selectionList->isEmpty());36 }77 }377838-public function testIsEmptyReturnsFalseWhenAnyListIsNotEmpty(): void79+public function testIsEmptyReturnsFalseWhenEntitiesAdded(): void39 {80 {40-$selectionList = new SelectionList(['p1'], []);81+$selectionList = new SelectionList();41-$this->assertFalse($selectionList->isEmpty());82+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);428343-$selectionList2 = new SelectionList([], ['n1']);84+$this->assertFalse($selectionList->isEmpty());44-$this->assertFalse($selectionList2->isEmpty());45 }85 }468647-public function testIsStaleChunkSelected(): void87+public function testMarkStaleAndIsStaleChunkSelected(): void48 {88 {49-$selectionList = new SelectionList([], [], true);89+$selectionList = new SelectionList();50-$this->assertTrue($selectionList->isStaleChunkSelected());90+91+$this->assertFalse($selectionList->isStaleChunkSelected());92+93+$selectionList->markStale();519452-$selectionList2 = new SelectionList([], [], false);95+$this->assertTrue($selectionList->isStaleChunkSelected());53-$this->assertFalse($selectionList2->isStaleChunkSelected());54 }96 }559756public function testIsFullChunk(): void98public function testIsFullChunk(): void57 {99 {58-$chunkSize = 200;100+$selectionList = new SelectionList();59-101+$selectionList->setChunkSize(self::CHUNK_SIZE);60-$fullList = range(1, $chunkSize);102+61-$selectionList = new SelectionList(103+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, self::CHUNK_SIZE));62- priorityEntityIdList: $fullList,104+63- normalEntityIdList: [],105+$this->assertTrue($selectionList->isFullChunk());64- chunkSize: $chunkSize,106+ }65- );107+108+public function testIsNotFullChunkWhenBelowChunkSize(): void109+ {110+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);111+112+$selectionList = new SelectionList();113+$selectionList->setChunkSize(self::CHUNK_SIZE);114+115+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range(1, $halfRange));116+117+$this->assertFalse($selectionList->isFullChunk());118+ }119+120+public function testIsFullChunkAcrossMultiplePriorityGroups(): void121+ {122+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);123+124+$selectionList = new SelectionList();125+$selectionList->setChunkSize(self::CHUNK_SIZE);126+127+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, $halfRange));128+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range($halfRange + 1, self::CHUNK_SIZE));129+130+$this->assertTrue($selectionList->isFullChunk());131+ }132+133+public function testSetChunkSizeAffectsIsFullChunk(): void134+ {135+$selectionList = new SelectionList();136+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [1, 2, 3]);137+138+$selectionList->setChunkSize(3);66$this->assertTrue($selectionList->isFullChunk());139$this->assertTrue($selectionList->isFullChunk());6714068-$halfRange = (int) ceil($chunkSize / 2);141+$selectionList->setChunkSize(50);69-142+$this->assertFalse($selectionList->isFullChunk());70-$notFullList = range(1, $halfRange);71-$selectionList2 = new SelectionList(72- priorityEntityIdList: $notFullList,73- normalEntityIdList: [],74- chunkSize: $chunkSize,75- );76-$this->assertFalse($selectionList2->isFullChunk());77-78-$priorityRange = range(1, $halfRange);79-$normalRange = range($halfRange + 1, $chunkSize);80-81-$selectionList3 = new SelectionList(82- priorityEntityIdList: $priorityRange,83- normalEntityIdList: $normalRange,84- chunkSize: $chunkSize,85- );86-$this->assertTrue($selectionList3->isFullChunk());87 }143 }88}144}</selection>” selected.
Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
Expand
Listen
Gemini said
Gemini said
Here is a precise and concise summary of the code selection, which refactors
SelectionListTest
to accommodate a shift from fixed high/normal priority properties to a more dynamic, enum-driven priority group architecture.
Refactored Priority Handling
Refactored Priority Handling
Dynamic Priority Groups:
Replaces fixed high/normal array parameters with the
QueuePriorityEnum
(
HIGH
,
NORMAL
,
LOW
), allowing entity lists to be managed dynamically by group types.
Merged Registrations:
Validates that multiple
addEntityList()
calls targeting the same priority level properly merge their data instead of overwriting it.
Group Querying:
Tests new methods
getEntityListItemsByGroup()
and
getEntityListGroups()
to retrieve group-specific IDs or an array of active group names (e.g.,
['high', 'normal']
).
Updated State and Count Validations
Updated State and Count Validations
Instantiation:
Tests now instantiate
SelectionList
without initial constructor arguments, using setters and action methods instead.
Empty States:
Updates assertions (
isEmpty()
) to verify state based on whether any entities have been dynamically added, rather than checking pre-defined constructor arrays.
Stale Flags:
Changes from passing a
stale
boolean via the constructor to explicitly triggering a mutable
$selectionList->markStale()
method.
Chunk Capacity Behavior
Chunk Capacity Behavior
Flexible Chunk Sizes:
Introduces a
setChunkSize()
method, replacing the constructor-configured chunk boundary.
Capacity Assertions:
Retains and updates the logic for
isFullChunk()
, ensuring it accurately evaluates capacity when elements span multiple dynamic priority groups or when the chunk limit is altered mid-lifecycle.
Good response
Bad response
Share & export
Copy
Show more options
Copy prompt
You said Are there any issues or potential bolltenecks
You said
Are there any issues or potential bolltenecks
Listen
Show thinking
Gemini said
Gemini said
Based on the test diff you provided, we can infer a few potential issues and architectural bottlenecks in the underlying
SelectionList
implementation. While the tests are well-structured, the behavior they describe hints at a few areas you might want to keep an eye on, particularly for an Elasticsearch (ES) processor queue.
Here are the potential issues and bottlenecks to consider:
1. Array Merging Overhead (Performance)
1. Array Merging Overhead (Performance)
The
testAddEntityListMergesMultipleCallsForSamePriority
test shows that calling
addEntityList()
multiple times for the same priority group merges the arrays.
The Bottleneck:
If the underlying implementation uses
array_merge()
inside a loop to append these IDs, it creates a new array in memory every time it's called. If you are processing thousands of entities and appending them in small batches, this can lead to memory bloat and CPU degradation due to constant array reallocation.
Mitigation:
Ensure the implementation handles batch appends efficiently (e.g., using the spread operator
[...$existing, ...$new]
or appending via references) or groups the arrays before doing a single merge.
2. Lack of Uniqueness/Deduplication (Logic)
2. Lack of Uniqueness/Deduplication (Logic)
None of the tests explicitly verify what happens if duplicate IDs are added. For example, if you call
addEntityList(QueuePriorityEnum::HIGH, [1, 2])
and then
addEntityList(QueuePriorityEnum::HIGH, [2, 3])
.
The Issue:
Does the getter return
[1, 2, 2, 3]
or
[1, 2, 3]
? If duplicates are not filtered out, your ES processor might end up indexing the same entity multiple times in a single chunk, which wastes I/O and processor cycles.
Mitigation:
The underlying class should ideally enforce uniqueness (e.g., using
array_unique()
before resolving the chunk, or using ID keys as associative array keys to naturally prevent duplicates).
3. Memory Consumption with Large Chunks (Scalability)
3. Memory Consumption with Large Chunks (Scalability)
The tests introduce
setChunkSize()
. If this chunk size is configured to be very large (e.g., tens of thousands of IDs to bulk-send to Elasticsearch).
The Bottleneck:
Holding massive arrays of IDs in memory across different priority groups can quickly hit PHP memory limits, especially if this
SelectionList
object is kept alive during a long-running daemon or cron job.
Mitigation:
Monitor memory usage if
CHUNK_SIZE
grows, and ensure the
SelectionList
object is properly destroyed (or garbage collected) after the chunk is processed to free up memory.
4. Type Juggling
4. Type Juggling
In the original code, string IDs were used (
['p1', 'p2']
). In the refactored tests, integer IDs are used (
[1, 2]
).
The Issue:
If your system handles UUIDs (strings) vs. relational DB auto-increments (integers), make sure the underlying implementation uses strict comparisons (
===
) where necessary, especially if deduplicating arrays, to prevent PHP from juggling
'1'
and
1
improperly.
Would you like me to draft a quick test case to check how the class currently handles duplicate IDs, or is deduplication intentionally handled further down your pipeline?
Good response
Bad response
Share & export
Copy
Show more options
Copy prompt
You said what about non test files
You said
what about non test files
Listen
Show thinking
Gemini said
Gemini said
Since we don't have the actual
SelectionList.php
file, we have to reverse-engineer its implementation based on the test behaviors. Moving from a constructor-based, fixed-property model to a dynamic, mutable model introduces several potential pitfalls in the implementation file itself.
Here are the specific bottlenecks and issues to watch out for in the
SelectionList.php
source code:
1. The count() Method Implementation (Performance Trap)
1. The
count()
Method Implementation (Performance Trap)
The Risk:
If
count()
is implemented by calling
$this->getAllIds()
and counting the resulting merged array (e.g.,
return count($this->getAllIds());
), it will be highly inefficient. It would allocate a brand-new array in memory just to determine its length.
The Fix:
count()
should mathematically sum the sizes of the underlying group arrays without merging them:
return array_sum(array_map('count', $this->entityLists));
2. Loss of Immutability (State Management)
2. Loss of Immutability (State Management)...
|
[{"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":"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 I’m on page “<tabTitle>JY-20808 low priority indexing queue by Vasil-Jimi</tabTitle>” with “<selection>@@ -5,84 +5,140 @@5namespace Tests\\Unit\\Component\\ES\\Processor\\DTOs;5namespace Tests\\Unit\\Component\\ES\\Processor\\DTOs;667use Jiminny\\Component\\ES\\Processor\\DTOs\\SelectionList;7use Jiminny\\Component\\ES\\Processor\\DTOs\\SelectionList;8+use Jiminny\\Component\\ES\\QueuePriorityEnum;8use PHPUnit\\Framework\\Attributes\\CoversClass;9use PHPUnit\\Framework\\Attributes\\CoversClass;9use PHPUnit\\Framework\\TestCase;10use PHPUnit\\Framework\\TestCase;101111#[CoversClass(SelectionList::class)]12#[CoversClass(SelectionList::class)]12final class SelectionListTest extends TestCase13final class SelectionListTest extends TestCase13{14{14-public function testGetEntityIds(): void15+private const int CHUNK_SIZE = 100;16+17+public function testAddEntityListAndGetAllIds(): void18+ {19+$selectionList = new SelectionList();20+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);21+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);22+23+$this->assertSame([1, 2, 3, 4], $selectionList->getAllIds());24+ }25+26+public function testAddEntityListMergesMultipleCallsForSamePriority(): void27+ {28+$selectionList = new SelectionList();29+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);30+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [3, 4]);31+32+$this->assertSame([1, 2, 3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));33+ }34+35+public function testGetEntityListItemsByGroup(): void36+ {37+$selectionList = new SelectionList();38+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);39+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);40+$selectionList->addEntityList(QueuePriorityEnum::LOW, [5, 6]);41+42+$this->assertSame([1, 2], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));43+$this->assertSame([3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::NORMAL));44+$this->assertSame([5, 6], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::LOW));45+ }46+47+public function testGetEntityListItemsByGroupReturnsEmptyArrayForUnknownGroup(): void15 {48 {16-$priority = ['p1', 'p2'];49+$selectionList = new SelectionList();17-$normal = ['n1', 'n2'];50+18-$selectionList = new SelectionList($priority, $normal);51+$this->assertSame([], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));52+ }195320-$this->assertSame($priority, $selectionList->getHighPriorityEntityIds());54+public function testGetEntityListGroups(): void21-$this->assertSame($normal, $selectionList->getNormalPriorityEntityId());55+ {56+$selectionList = new SelectionList();57+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);58+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2]);225923-$this->assertSame(['p1', 'p2', 'n1', 'n2'], $selectionList->getAllIds());60+$this->assertSame(['high', 'normal'], $selectionList->getEntityListGroups());24 }61 }256226public function testCountReturnsTotalCount(): void63public function testCountReturnsTotalCount(): void27 {64 {28-$selectionList = new SelectionList(['p1'], ['n1', 'n2']);65+$selectionList = new SelectionList();66+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);67+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2, 3]);68+29$this->assertSame(3, $selectionList->count());69$this->assertSame(3, $selectionList->count());30 }70 }317132-public function testIsEmptyReturnsTrueWhenBothListsAreEmpty(): void72+public function testIsEmptyReturnsTrueWhenNoEntitiesAdded(): void33 {73 {34-$selectionList = new SelectionList([], []);74+$selectionList = new SelectionList();75+35$this->assertTrue($selectionList->isEmpty());76$this->assertTrue($selectionList->isEmpty());36 }77 }377838-public function testIsEmptyReturnsFalseWhenAnyListIsNotEmpty(): void79+public function testIsEmptyReturnsFalseWhenEntitiesAdded(): void39 {80 {40-$selectionList = new SelectionList(['p1'], []);81+$selectionList = new SelectionList();41-$this->assertFalse($selectionList->isEmpty());82+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);428343-$selectionList2 = new SelectionList([], ['n1']);84+$this->assertFalse($selectionList->isEmpty());44-$this->assertFalse($selectionList2->isEmpty());45 }85 }468647-public function testIsStaleChunkSelected(): void87+public function testMarkStaleAndIsStaleChunkSelected(): void48 {88 {49-$selectionList = new SelectionList([], [], true);89+$selectionList = new SelectionList();50-$this->assertTrue($selectionList->isStaleChunkSelected());90+91+$this->assertFalse($selectionList->isStaleChunkSelected());92+93+$selectionList->markStale();519452-$selectionList2 = new SelectionList([], [], false);95+$this->assertTrue($selectionList->isStaleChunkSelected());53-$this->assertFalse($selectionList2->isStaleChunkSelected());54 }96 }559756public function testIsFullChunk(): void98public function testIsFullChunk(): void57 {99 {58-$chunkSize = 200;100+$selectionList = new SelectionList();59-101+$selectionList->setChunkSize(self::CHUNK_SIZE);60-$fullList = range(1, $chunkSize);102+61-$selectionList = new SelectionList(103+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, self::CHUNK_SIZE));62- priorityEntityIdList: $fullList,104+63- normalEntityIdList: [],105+$this->assertTrue($selectionList->isFullChunk());64- chunkSize: $chunkSize,106+ }65- );107+108+public function testIsNotFullChunkWhenBelowChunkSize(): void109+ {110+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);111+112+$selectionList = new SelectionList();113+$selectionList->setChunkSize(self::CHUNK_SIZE);114+115+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range(1, $halfRange));116+117+$this->assertFalse($selectionList->isFullChunk());118+ }119+120+public function testIsFullChunkAcrossMultiplePriorityGroups(): void121+ {122+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);123+124+$selectionList = new SelectionList();125+$selectionList->setChunkSize(self::CHUNK_SIZE);126+127+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, $halfRange));128+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range($halfRange + 1, self::CHUNK_SIZE));129+130+$this->assertTrue($selectionList->isFullChunk());131+ }132+133+public function testSetChunkSizeAffectsIsFullChunk(): void134+ {135+$selectionList = new SelectionList();136+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [1, 2, 3]);137+138+$selectionList->setChunkSize(3);66$this->assertTrue($selectionList->isFullChunk());139$this->assertTrue($selectionList->isFullChunk());6714068-$halfRange = (int) ceil($chunkSize / 2);141+$selectionList->setChunkSize(50);69-142+$this->assertFalse($selectionList->isFullChunk());70-$notFullList = range(1, $halfRange);71-$selectionList2 = new SelectionList(72- priorityEntityIdList: $notFullList,73- normalEntityIdList: [],74- chunkSize: $chunkSize,75- );76-$this->assertFalse($selectionList2->isFullChunk());77-78-$priorityRange = range(1, $halfRange);79-$normalRange = range($halfRange + 1, $chunkSize);80-81-$selectionList3 = new SelectionList(82- priorityEntityIdList: $priorityRange,83- normalEntityIdList: $normalRange,84- chunkSize: $chunkSize,85- );86-$this->assertTrue($selectionList3->isFullChunk());87 }143 }88}144}</selection>” selected. Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.","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":"I’m on page “<tabTitle>JY-20808 low priority indexing queue by Vasil-Jimi</tabTitle>” with “<selection>@@ -5,84 +5,140 @@5namespace Tests\\Unit\\Component\\ES\\Processor\\DTOs;5namespace Tests\\Unit\\Component\\ES\\Processor\\DTOs;667use Jiminny\\Component\\ES\\Processor\\DTOs\\SelectionList;7use Jiminny\\Component\\ES\\Processor\\DTOs\\SelectionList;8+use Jiminny\\Component\\ES\\QueuePriorityEnum;8use PHPUnit\\Framework\\Attributes\\CoversClass;9use PHPUnit\\Framework\\Attributes\\CoversClass;9use PHPUnit\\Framework\\TestCase;10use PHPUnit\\Framework\\TestCase;101111#[CoversClass(SelectionList::class)]12#[CoversClass(SelectionList::class)]12final class SelectionListTest extends TestCase13final class SelectionListTest extends TestCase13{14{14-public function testGetEntityIds(): void15+private const int CHUNK_SIZE = 100;16+17+public function testAddEntityListAndGetAllIds(): void18+ {19+$selectionList = new SelectionList();20+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);21+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);22+23+$this->assertSame([1, 2, 3, 4], $selectionList->getAllIds());24+ }25+26+public function testAddEntityListMergesMultipleCallsForSamePriority(): void27+ {28+$selectionList = new SelectionList();29+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);30+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [3, 4]);31+32+$this->assertSame([1, 2, 3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));33+ }34+35+public function testGetEntityListItemsByGroup(): void36+ {37+$selectionList = new SelectionList();38+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);39+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);40+$selectionList->addEntityList(QueuePriorityEnum::LOW, [5, 6]);41+42+$this->assertSame([1, 2], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));43+$this->assertSame([3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::NORMAL));44+$this->assertSame([5, 6], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::LOW));45+ }46+47+public function testGetEntityListItemsByGroupReturnsEmptyArrayForUnknownGroup(): void15 {48 {16-$priority = ['p1', 'p2'];49+$selectionList = new SelectionList();17-$normal = ['n1', 'n2'];50+18-$selectionList = new SelectionList($priority, $normal);51+$this->assertSame([], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));52+ }195320-$this->assertSame($priority, $selectionList->getHighPriorityEntityIds());54+public function testGetEntityListGroups(): void21-$this->assertSame($normal, $selectionList->getNormalPriorityEntityId());55+ {56+$selectionList = new SelectionList();57+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);58+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2]);225923-$this->assertSame(['p1', 'p2', 'n1', 'n2'], $selectionList->getAllIds());60+$this->assertSame(['high', 'normal'], $selectionList->getEntityListGroups());24 }61 }256226public function testCountReturnsTotalCount(): void63public function testCountReturnsTotalCount(): void27 {64 {28-$selectionList = new SelectionList(['p1'], ['n1', 'n2']);65+$selectionList = new SelectionList();66+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);67+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2, 3]);68+29$this->assertSame(3, $selectionList->count());69$this->assertSame(3, $selectionList->count());30 }70 }317132-public function testIsEmptyReturnsTrueWhenBothListsAreEmpty(): void72+public function testIsEmptyReturnsTrueWhenNoEntitiesAdded(): void33 {73 {34-$selectionList = new SelectionList([], []);74+$selectionList = new SelectionList();75+35$this->assertTrue($selectionList->isEmpty());76$this->assertTrue($selectionList->isEmpty());36 }77 }377838-public function testIsEmptyReturnsFalseWhenAnyListIsNotEmpty(): void79+public function testIsEmptyReturnsFalseWhenEntitiesAdded(): void39 {80 {40-$selectionList = new SelectionList(['p1'], []);81+$selectionList = new SelectionList();41-$this->assertFalse($selectionList->isEmpty());82+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);428343-$selectionList2 = new SelectionList([], ['n1']);84+$this->assertFalse($selectionList->isEmpty());44-$this->assertFalse($selectionList2->isEmpty());45 }85 }468647-public function testIsStaleChunkSelected(): void87+public function testMarkStaleAndIsStaleChunkSelected(): void48 {88 {49-$selectionList = new SelectionList([], [], true);89+$selectionList = new SelectionList();50-$this->assertTrue($selectionList->isStaleChunkSelected());90+91+$this->assertFalse($selectionList->isStaleChunkSelected());92+93+$selectionList->markStale();519452-$selectionList2 = new SelectionList([], [], false);95+$this->assertTrue($selectionList->isStaleChunkSelected());53-$this->assertFalse($selectionList2->isStaleChunkSelected());54 }96 }559756public function testIsFullChunk(): void98public function testIsFullChunk(): void57 {99 {58-$chunkSize = 200;100+$selectionList = new SelectionList();59-101+$selectionList->setChunkSize(self::CHUNK_SIZE);60-$fullList = range(1, $chunkSize);102+61-$selectionList = new SelectionList(103+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, self::CHUNK_SIZE));62- priorityEntityIdList: $fullList,104+63- normalEntityIdList: [],105+$this->assertTrue($selectionList->isFullChunk());64- chunkSize: $chunkSize,106+ }65- );107+108+public function testIsNotFullChunkWhenBelowChunkSize(): void109+ {110+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);111+112+$selectionList = new SelectionList();113+$selectionList->setChunkSize(self::CHUNK_SIZE);114+115+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range(1, $halfRange));116+117+$this->assertFalse($selectionList->isFullChunk());118+ }119+120+public function testIsFullChunkAcrossMultiplePriorityGroups(): void121+ {122+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);123+124+$selectionList = new SelectionList();125+$selectionList->setChunkSize(self::CHUNK_SIZE);126+127+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, $halfRange));128+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range($halfRange + 1, self::CHUNK_SIZE));129+130+$this->assertTrue($selectionList->isFullChunk());131+ }132+133+public function testSetChunkSizeAffectsIsFullChunk(): void134+ {135+$selectionList = new SelectionList();136+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [1, 2, 3]);137+138+$selectionList->setChunkSize(3);66$this->assertTrue($selectionList->isFullChunk());139$this->assertTrue($selectionList->isFullChunk());6714068-$halfRange = (int) ceil($chunkSize / 2);141+$selectionList->setChunkSize(50);69-142+$this->assertFalse($selectionList->isFullChunk());70-$notFullList = range(1, $halfRange);71-$selectionList2 = new SelectionList(72- priorityEntityIdList: $notFullList,73- normalEntityIdList: [],74- chunkSize: $chunkSize,75- );76-$this->assertFalse($selectionList2->isFullChunk());77-78-$priorityRange = range(1, $halfRange);79-$normalRange = range($halfRange + 1, $chunkSize);80-81-$selectionList3 = new SelectionList(82- priorityEntityIdList: $priorityRange,83- normalEntityIdList: $normalRange,84- chunkSize: $chunkSize,85- );86-$this->assertTrue($selectionList3->isFullChunk());87 }143 }88}144}</selection>” selected.","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Expand","depth":21,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"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":"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":"Here is a precise and concise summary of the code selection, which refactors","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SelectionListTest","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"to accommodate a shift from fixed high/normal priority properties to a more dynamic, enum-driven priority group architecture.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Refactored Priority Handling","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Refactored Priority Handling","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Dynamic Priority Groups:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Replaces fixed high/normal array parameters with the","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"QueuePriorityEnum","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"HIGH","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"NORMAL","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"LOW","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"), allowing entity lists to be managed dynamically by group types.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Merged Registrations:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Validates that multiple","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"addEntityList()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"calls targeting the same priority level properly merge their data instead of overwriting it.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Group Querying:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Tests new methods","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"getEntityListItemsByGroup()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"and","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"getEntityListGroups()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"to retrieve group-specific IDs or an array of active group names (e.g.,","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"['high', 'normal']","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":").","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Updated State and Count Validations","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Updated State and Count Validations","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Instantiation:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Tests now instantiate","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SelectionList","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"without initial constructor arguments, using setters and action methods instead.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Empty States:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Updates assertions (","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"isEmpty()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":") to verify state based on whether any entities have been dynamically added, rather than checking pre-defined constructor arrays.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Stale Flags:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Changes from passing a","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"stale","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"boolean via the constructor to explicitly triggering a mutable","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$selectionList->markStale()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"method.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Chunk Capacity Behavior","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Chunk Capacity Behavior","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Flexible Chunk Sizes:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Introduces a","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"setChunkSize()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"method, replacing the constructor-configured chunk boundary.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Capacity Assertions:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Retains and updates the logic for","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"isFullChunk()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":", ensuring it accurately evaluates capacity when elements span multiple dynamic priority groups or when the chunk limit is altered mid-lifecycle.","depth":26,"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":"AXHeading","text":"You said Are there any issues or potential bolltenecks","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":"Are there any issues or potential bolltenecks","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":"Based on the test diff you provided, we can infer a few potential issues and architectural bottlenecks in the underlying","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SelectionList","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"implementation. While the tests are well-structured, the behavior they describe hints at a few areas you might want to keep an eye on, particularly for an Elasticsearch (ES) processor queue.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Here are the potential issues and bottlenecks to consider:","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"1. Array Merging Overhead (Performance)","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1. Array Merging Overhead (Performance)","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"testAddEntityListMergesMultipleCallsForSamePriority","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"test shows that calling","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"addEntityList()","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"multiple times for the same priority group merges the arrays.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The Bottleneck:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"If the underlying implementation uses","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"array_merge()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"inside a loop to append these IDs, it creates a new array in memory every time it's called. If you are processing thousands of entities and appending them in small batches, this can lead to memory bloat and CPU degradation due to constant array reallocation.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Mitigation:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Ensure the implementation handles batch appends efficiently (e.g., using the spread operator","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"[...$existing, ...$new]","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"or appending via references) or groups the arrays before doing a single merge.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"2. Lack of Uniqueness/Deduplication (Logic)","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2. Lack of Uniqueness/Deduplication (Logic)","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"None of the tests explicitly verify what happens if duplicate IDs are added. For example, if you call","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"addEntityList(QueuePriorityEnum::HIGH, [1, 2])","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"and then","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"addEntityList(QueuePriorityEnum::HIGH, [2, 3])","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":".","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The Issue:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Does the getter return","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"[1, 2, 2, 3]","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"or","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"[1, 2, 3]","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"? If duplicates are not filtered out, your ES processor might end up indexing the same entity multiple times in a single chunk, which wastes I/O and processor cycles.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Mitigation:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The underlying class should ideally enforce uniqueness (e.g., using","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"array_unique()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"before resolving the chunk, or using ID keys as associative array keys to naturally prevent duplicates).","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"3. Memory Consumption with Large Chunks (Scalability)","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3. Memory Consumption with Large Chunks (Scalability)","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The tests introduce","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"setChunkSize()","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":". If this chunk size is configured to be very large (e.g., tens of thousands of IDs to bulk-send to Elasticsearch).","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The Bottleneck:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Holding massive arrays of IDs in memory across different priority groups can quickly hit PHP memory limits, especially if this","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SelectionList","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"object is kept alive during a long-running daemon or cron job.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Mitigation:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Monitor memory usage if","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"CHUNK_SIZE","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"grows, and ensure the","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SelectionList","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"object is properly destroyed (or garbage collected) after the chunk is processed to free up memory.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"4. Type Juggling","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"4. Type Juggling","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"In the original code, string IDs were used (","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"['p1', 'p2']","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"). In the refactored tests, integer IDs are used (","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"[1, 2]","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":").","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The Issue:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"If your system handles UUIDs (strings) vs. relational DB auto-increments (integers), make sure the underlying implementation uses strict comparisons (","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"===","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":") where necessary, especially if deduplicating arrays, to prevent PHP from juggling","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"'1'","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"and","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"improperly.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Would you like me to draft a quick test case to check how the class currently handles duplicate IDs, or is deduplication intentionally handled further down your pipeline?","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":"AXHeading","text":"You said what about non test files","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":"what about non test files","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":"Since we don't have the actual","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SelectionList.php","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"file, we have to reverse-engineer its implementation based on the test behaviors. Moving from a constructor-based, fixed-property model to a dynamic, mutable model introduces several potential pitfalls in the implementation file itself.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Here are the specific bottlenecks and issues to watch out for in the","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SelectionList.php","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"source code:","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"1. The count() Method Implementation (Performance Trap)","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1. The","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"count()","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Method Implementation (Performance Trap)","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The Risk:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"If","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"count()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"is implemented by calling","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$this->getAllIds()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"and counting the resulting merged array (e.g.,","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"return count($this->getAllIds());","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"), it will be highly inefficient. It would allocate a brand-new array in memory just to determine its length.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The Fix:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"count()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"should mathematically sum the sizes of the underlying group arrays without merging them:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"return array_sum(array_map('count', $this->entityLists));","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"2. Loss of Immutability (State Management)","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2. Loss of Immutability (State Management)","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"}]...
|
2737255412499969554
|
8165702397781963159
|
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
Copy prompt
You said I’m on page “<tabTitle>JY-20808 low priority indexing queue by Vasil-Jimi</tabTitle>” with “<selection>@@ -5,84 +5,140 @@5namespace Tests\Unit\Component\ES\Processor\DTOs;5namespace Tests\Unit\Component\ES\Processor\DTOs;667use Jiminny\Component\ES\Processor\DTOs\SelectionList;7use Jiminny\Component\ES\Processor\DTOs\SelectionList;8+use Jiminny\Component\ES\QueuePriorityEnum;8use PHPUnit\Framework\Attributes\CoversClass;9use PHPUnit\Framework\Attributes\CoversClass;9use PHPUnit\Framework\TestCase;10use PHPUnit\Framework\TestCase;101111#[CoversClass(SelectionList::class)]12#[CoversClass(SelectionList::class)]12final class SelectionListTest extends TestCase13final class SelectionListTest extends TestCase13{14{14-public function testGetEntityIds(): void15+private const int CHUNK_SIZE = 100;16+17+public function testAddEntityListAndGetAllIds(): void18+ {19+$selectionList = new SelectionList();20+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);21+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);22+23+$this->assertSame([1, 2, 3, 4], $selectionList->getAllIds());24+ }25+26+public function testAddEntityListMergesMultipleCallsForSamePriority(): void27+ {28+$selectionList = new SelectionList();29+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);30+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [3, 4]);31+32+$this->assertSame([1, 2, 3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));33+ }34+35+public function testGetEntityListItemsByGroup(): void36+ {37+$selectionList = new SelectionList();38+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);39+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);40+$selectionList->addEntityList(QueuePriorityEnum::LOW, [5, 6]);41+42+$this->assertSame([1, 2], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));43+$this->assertSame([3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::NORMAL));44+$this->assertSame([5, 6], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::LOW));45+ }46+47+public function testGetEntityListItemsByGroupReturnsEmptyArrayForUnknownGroup(): void15 {48 {16-$priority = ['p1', 'p2'];49+$selectionList = new SelectionList();17-$normal = ['n1', 'n2'];50+18-$selectionList = new SelectionList($priority, $normal);51+$this->assertSame([], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));52+ }195320-$this->assertSame($priority, $selectionList->getHighPriorityEntityIds());54+public function testGetEntityListGroups(): void21-$this->assertSame($normal, $selectionList->getNormalPriorityEntityId());55+ {56+$selectionList = new SelectionList();57+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);58+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2]);225923-$this->assertSame(['p1', 'p2', 'n1', 'n2'], $selectionList->getAllIds());60+$this->assertSame(['high', 'normal'], $selectionList->getEntityListGroups());24 }61 }256226public function testCountReturnsTotalCount(): void63public function testCountReturnsTotalCount(): void27 {64 {28-$selectionList = new SelectionList(['p1'], ['n1', 'n2']);65+$selectionList = new SelectionList();66+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);67+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2, 3]);68+29$this->assertSame(3, $selectionList->count());69$this->assertSame(3, $selectionList->count());30 }70 }317132-public function testIsEmptyReturnsTrueWhenBothListsAreEmpty(): void72+public function testIsEmptyReturnsTrueWhenNoEntitiesAdded(): void33 {73 {34-$selectionList = new SelectionList([], []);74+$selectionList = new SelectionList();75+35$this->assertTrue($selectionList->isEmpty());76$this->assertTrue($selectionList->isEmpty());36 }77 }377838-public function testIsEmptyReturnsFalseWhenAnyListIsNotEmpty(): void79+public function testIsEmptyReturnsFalseWhenEntitiesAdded(): void39 {80 {40-$selectionList = new SelectionList(['p1'], []);81+$selectionList = new SelectionList();41-$this->assertFalse($selectionList->isEmpty());82+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);428343-$selectionList2 = new SelectionList([], ['n1']);84+$this->assertFalse($selectionList->isEmpty());44-$this->assertFalse($selectionList2->isEmpty());45 }85 }468647-public function testIsStaleChunkSelected(): void87+public function testMarkStaleAndIsStaleChunkSelected(): void48 {88 {49-$selectionList = new SelectionList([], [], true);89+$selectionList = new SelectionList();50-$this->assertTrue($selectionList->isStaleChunkSelected());90+91+$this->assertFalse($selectionList->isStaleChunkSelected());92+93+$selectionList->markStale();519452-$selectionList2 = new SelectionList([], [], false);95+$this->assertTrue($selectionList->isStaleChunkSelected());53-$this->assertFalse($selectionList2->isStaleChunkSelected());54 }96 }559756public function testIsFullChunk(): void98public function testIsFullChunk(): void57 {99 {58-$chunkSize = 200;100+$selectionList = new SelectionList();59-101+$selectionList->setChunkSize(self::CHUNK_SIZE);60-$fullList = range(1, $chunkSize);102+61-$selectionList = new SelectionList(103+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, self::CHUNK_SIZE));62- priorityEntityIdList: $fullList,104+63- normalEntityIdList: [],105+$this->assertTrue($selectionList->isFullChunk());64- chunkSize: $chunkSize,106+ }65- );107+108+public function testIsNotFullChunkWhenBelowChunkSize(): void109+ {110+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);111+112+$selectionList = new SelectionList();113+$selectionList->setChunkSize(self::CHUNK_SIZE);114+115+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range(1, $halfRange));116+117+$this->assertFalse($selectionList->isFullChunk());118+ }119+120+public function testIsFullChunkAcrossMultiplePriorityGroups(): void121+ {122+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);123+124+$selectionList = new SelectionList();125+$selectionList->setChunkSize(self::CHUNK_SIZE);126+127+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, $halfRange));128+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range($halfRange + 1, self::CHUNK_SIZE));129+130+$this->assertTrue($selectionList->isFullChunk());131+ }132+133+public function testSetChunkSizeAffectsIsFullChunk(): void134+ {135+$selectionList = new SelectionList();136+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [1, 2, 3]);137+138+$selectionList->setChunkSize(3);66$this->assertTrue($selectionList->isFullChunk());139$this->assertTrue($selectionList->isFullChunk());6714068-$halfRange = (int) ceil($chunkSize / 2);141+$selectionList->setChunkSize(50);69-142+$this->assertFalse($selectionList->isFullChunk());70-$notFullList = range(1, $halfRange);71-$selectionList2 = new SelectionList(72- priorityEntityIdList: $notFullList,73- normalEntityIdList: [],74- chunkSize: $chunkSize,75- );76-$this->assertFalse($selectionList2->isFullChunk());77-78-$priorityRange = range(1, $halfRange);79-$normalRange = range($halfRange + 1, $chunkSize);80-81-$selectionList3 = new SelectionList(82- priorityEntityIdList: $priorityRange,83- normalEntityIdList: $normalRange,84- chunkSize: $chunkSize,85- );86-$this->assertTrue($selectionList3->isFullChunk());87 }143 }88}144}</selection>” selected. Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
You said
I’m on page “<tabTitle>JY-20808 low priority indexing queue by Vasil-Jimi</tabTitle>” with “<selection>@@ -5,84 +5,140 @@5namespace Tests\Unit\Component\ES\Processor\DTOs;5namespace Tests\Unit\Component\ES\Processor\DTOs;667use Jiminny\Component\ES\Processor\DTOs\SelectionList;7use Jiminny\Component\ES\Processor\DTOs\SelectionList;8+use Jiminny\Component\ES\QueuePriorityEnum;8use PHPUnit\Framework\Attributes\CoversClass;9use PHPUnit\Framework\Attributes\CoversClass;9use PHPUnit\Framework\TestCase;10use PHPUnit\Framework\TestCase;101111#[CoversClass(SelectionList::class)]12#[CoversClass(SelectionList::class)]12final class SelectionListTest extends TestCase13final class SelectionListTest extends TestCase13{14{14-public function testGetEntityIds(): void15+private const int CHUNK_SIZE = 100;16+17+public function testAddEntityListAndGetAllIds(): void18+ {19+$selectionList = new SelectionList();20+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);21+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);22+23+$this->assertSame([1, 2, 3, 4], $selectionList->getAllIds());24+ }25+26+public function testAddEntityListMergesMultipleCallsForSamePriority(): void27+ {28+$selectionList = new SelectionList();29+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);30+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [3, 4]);31+32+$this->assertSame([1, 2, 3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));33+ }34+35+public function testGetEntityListItemsByGroup(): void36+ {37+$selectionList = new SelectionList();38+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);39+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);40+$selectionList->addEntityList(QueuePriorityEnum::LOW, [5, 6]);41+42+$this->assertSame([1, 2], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));43+$this->assertSame([3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::NORMAL));44+$this->assertSame([5, 6], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::LOW));45+ }46+47+public function testGetEntityListItemsByGroupReturnsEmptyArrayForUnknownGroup(): void15 {48 {16-$priority = ['p1', 'p2'];49+$selectionList = new SelectionList();17-$normal = ['n1', 'n2'];50+18-$selectionList = new SelectionList($priority, $normal);51+$this->assertSame([], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));52+ }195320-$this->assertSame($priority, $selectionList->getHighPriorityEntityIds());54+public function testGetEntityListGroups(): void21-$this->assertSame($normal, $selectionList->getNormalPriorityEntityId());55+ {56+$selectionList = new SelectionList();57+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);58+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2]);225923-$this->assertSame(['p1', 'p2', 'n1', 'n2'], $selectionList->getAllIds());60+$this->assertSame(['high', 'normal'], $selectionList->getEntityListGroups());24 }61 }256226public function testCountReturnsTotalCount(): void63public function testCountReturnsTotalCount(): void27 {64 {28-$selectionList = new SelectionList(['p1'], ['n1', 'n2']);65+$selectionList = new SelectionList();66+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);67+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2, 3]);68+29$this->assertSame(3, $selectionList->count());69$this->assertSame(3, $selectionList->count());30 }70 }317132-public function testIsEmptyReturnsTrueWhenBothListsAreEmpty(): void72+public function testIsEmptyReturnsTrueWhenNoEntitiesAdded(): void33 {73 {34-$selectionList = new SelectionList([], []);74+$selectionList = new SelectionList();75+35$this->assertTrue($selectionList->isEmpty());76$this->assertTrue($selectionList->isEmpty());36 }77 }377838-public function testIsEmptyReturnsFalseWhenAnyListIsNotEmpty(): void79+public function testIsEmptyReturnsFalseWhenEntitiesAdded(): void39 {80 {40-$selectionList = new SelectionList(['p1'], []);81+$selectionList = new SelectionList();41-$this->assertFalse($selectionList->isEmpty());82+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);428343-$selectionList2 = new SelectionList([], ['n1']);84+$this->assertFalse($selectionList->isEmpty());44-$this->assertFalse($selectionList2->isEmpty());45 }85 }468647-public function testIsStaleChunkSelected(): void87+public function testMarkStaleAndIsStaleChunkSelected(): void48 {88 {49-$selectionList = new SelectionList([], [], true);89+$selectionList = new SelectionList();50-$this->assertTrue($selectionList->isStaleChunkSelected());90+91+$this->assertFalse($selectionList->isStaleChunkSelected());92+93+$selectionList->markStale();519452-$selectionList2 = new SelectionList([], [], false);95+$this->assertTrue($selectionList->isStaleChunkSelected());53-$this->assertFalse($selectionList2->isStaleChunkSelected());54 }96 }559756public function testIsFullChunk(): void98public function testIsFullChunk(): void57 {99 {58-$chunkSize = 200;100+$selectionList = new SelectionList();59-101+$selectionList->setChunkSize(self::CHUNK_SIZE);60-$fullList = range(1, $chunkSize);102+61-$selectionList = new SelectionList(103+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, self::CHUNK_SIZE));62- priorityEntityIdList: $fullList,104+63- normalEntityIdList: [],105+$this->assertTrue($selectionList->isFullChunk());64- chunkSize: $chunkSize,106+ }65- );107+108+public function testIsNotFullChunkWhenBelowChunkSize(): void109+ {110+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);111+112+$selectionList = new SelectionList();113+$selectionList->setChunkSize(self::CHUNK_SIZE);114+115+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range(1, $halfRange));116+117+$this->assertFalse($selectionList->isFullChunk());118+ }119+120+public function testIsFullChunkAcrossMultiplePriorityGroups(): void121+ {122+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);123+124+$selectionList = new SelectionList();125+$selectionList->setChunkSize(self::CHUNK_SIZE);126+127+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, $halfRange));128+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range($halfRange + 1, self::CHUNK_SIZE));129+130+$this->assertTrue($selectionList->isFullChunk());131+ }132+133+public function testSetChunkSizeAffectsIsFullChunk(): void134+ {135+$selectionList = new SelectionList();136+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [1, 2, 3]);137+138+$selectionList->setChunkSize(3);66$this->assertTrue($selectionList->isFullChunk());139$this->assertTrue($selectionList->isFullChunk());6714068-$halfRange = (int) ceil($chunkSize / 2);141+$selectionList->setChunkSize(50);69-142+$this->assertFalse($selectionList->isFullChunk());70-$notFullList = range(1, $halfRange);71-$selectionList2 = new SelectionList(72- priorityEntityIdList: $notFullList,73- normalEntityIdList: [],74- chunkSize: $chunkSize,75- );76-$this->assertFalse($selectionList2->isFullChunk());77-78-$priorityRange = range(1, $halfRange);79-$normalRange = range($halfRange + 1, $chunkSize);80-81-$selectionList3 = new SelectionList(82- priorityEntityIdList: $priorityRange,83- normalEntityIdList: $normalRange,84- chunkSize: $chunkSize,85- );86-$this->assertTrue($selectionList3->isFullChunk());87 }143 }88}144}</selection>” selected.
Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
Expand
Listen
Gemini said
Gemini said
Here is a precise and concise summary of the code selection, which refactors
SelectionListTest
to accommodate a shift from fixed high/normal priority properties to a more dynamic, enum-driven priority group architecture.
Refactored Priority Handling
Refactored Priority Handling
Dynamic Priority Groups:
Replaces fixed high/normal array parameters with the
QueuePriorityEnum
(
HIGH
,
NORMAL
,
LOW
), allowing entity lists to be managed dynamically by group types.
Merged Registrations:
Validates that multiple
addEntityList()
calls targeting the same priority level properly merge their data instead of overwriting it.
Group Querying:
Tests new methods
getEntityListItemsByGroup()
and
getEntityListGroups()
to retrieve group-specific IDs or an array of active group names (e.g.,
['high', 'normal']
).
Updated State and Count Validations
Updated State and Count Validations
Instantiation:
Tests now instantiate
SelectionList
without initial constructor arguments, using setters and action methods instead.
Empty States:
Updates assertions (
isEmpty()
) to verify state based on whether any entities have been dynamically added, rather than checking pre-defined constructor arrays.
Stale Flags:
Changes from passing a
stale
boolean via the constructor to explicitly triggering a mutable
$selectionList->markStale()
method.
Chunk Capacity Behavior
Chunk Capacity Behavior
Flexible Chunk Sizes:
Introduces a
setChunkSize()
method, replacing the constructor-configured chunk boundary.
Capacity Assertions:
Retains and updates the logic for
isFullChunk()
, ensuring it accurately evaluates capacity when elements span multiple dynamic priority groups or when the chunk limit is altered mid-lifecycle.
Good response
Bad response
Share & export
Copy
Show more options
Copy prompt
You said Are there any issues or potential bolltenecks
You said
Are there any issues or potential bolltenecks
Listen
Show thinking
Gemini said
Gemini said
Based on the test diff you provided, we can infer a few potential issues and architectural bottlenecks in the underlying
SelectionList
implementation. While the tests are well-structured, the behavior they describe hints at a few areas you might want to keep an eye on, particularly for an Elasticsearch (ES) processor queue.
Here are the potential issues and bottlenecks to consider:
1. Array Merging Overhead (Performance)
1. Array Merging Overhead (Performance)
The
testAddEntityListMergesMultipleCallsForSamePriority
test shows that calling
addEntityList()
multiple times for the same priority group merges the arrays.
The Bottleneck:
If the underlying implementation uses
array_merge()
inside a loop to append these IDs, it creates a new array in memory every time it's called. If you are processing thousands of entities and appending them in small batches, this can lead to memory bloat and CPU degradation due to constant array reallocation.
Mitigation:
Ensure the implementation handles batch appends efficiently (e.g., using the spread operator
[...$existing, ...$new]
or appending via references) or groups the arrays before doing a single merge.
2. Lack of Uniqueness/Deduplication (Logic)
2. Lack of Uniqueness/Deduplication (Logic)
None of the tests explicitly verify what happens if duplicate IDs are added. For example, if you call
addEntityList(QueuePriorityEnum::HIGH, [1, 2])
and then
addEntityList(QueuePriorityEnum::HIGH, [2, 3])
.
The Issue:
Does the getter return
[1, 2, 2, 3]
or
[1, 2, 3]
? If duplicates are not filtered out, your ES processor might end up indexing the same entity multiple times in a single chunk, which wastes I/O and processor cycles.
Mitigation:
The underlying class should ideally enforce uniqueness (e.g., using
array_unique()
before resolving the chunk, or using ID keys as associative array keys to naturally prevent duplicates).
3. Memory Consumption with Large Chunks (Scalability)
3. Memory Consumption with Large Chunks (Scalability)
The tests introduce
setChunkSize()
. If this chunk size is configured to be very large (e.g., tens of thousands of IDs to bulk-send to Elasticsearch).
The Bottleneck:
Holding massive arrays of IDs in memory across different priority groups can quickly hit PHP memory limits, especially if this
SelectionList
object is kept alive during a long-running daemon or cron job.
Mitigation:
Monitor memory usage if
CHUNK_SIZE
grows, and ensure the
SelectionList
object is properly destroyed (or garbage collected) after the chunk is processed to free up memory.
4. Type Juggling
4. Type Juggling
In the original code, string IDs were used (
['p1', 'p2']
). In the refactored tests, integer IDs are used (
[1, 2]
).
The Issue:
If your system handles UUIDs (strings) vs. relational DB auto-increments (integers), make sure the underlying implementation uses strict comparisons (
===
) where necessary, especially if deduplicating arrays, to prevent PHP from juggling
'1'
and
1
improperly.
Would you like me to draft a quick test case to check how the class currently handles duplicate IDs, or is deduplication intentionally handled further down your pipeline?
Good response
Bad response
Share & export
Copy
Show more options
Copy prompt
You said what about non test files
You said
what about non test files
Listen
Show thinking
Gemini said
Gemini said
Since we don't have the actual
SelectionList.php
file, we have to reverse-engineer its implementation based on the test behaviors. Moving from a constructor-based, fixed-property model to a dynamic, mutable model introduces several potential pitfalls in the implementation file itself.
Here are the specific bottlenecks and issues to watch out for in the
SelectionList.php
source code:
1. The count() Method Implementation (Performance Trap)
1. The
count()
Method Implementation (Performance Trap)
The Risk:
If
count()
is implemented by calling
$this->getAllIds()
and counting the resulting merged array (e.g.,
return count($this->getAllIds());
), it will be highly inefficient. It would allocate a brand-new array in memory just to determine its length.
The Fix:
count()
should mathematically sum the sizes of the underlying group arrays without merging them:
return array_sum(array_map('count', $this->entityLists));
2. Loss of Immutability (State Management)
2. Loss of Immutability (State Management)...
|
55651
|
NULL
|
NULL
|
NULL
|
|
55657
|
1930
|
13
|
2026-05-19T06:36:14.694859+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779172574694_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-4bd github.com/jiminny/app/pull/12082/changes#diff-4bdd02759b5e0d060dcbc8c2dcb9bdbc3d0266d9c2e29956b9d63916dae1fdd7...
|
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
Copy prompt
You said I’m on page “<tabTitle>JY-20808 low priority indexing queue by Vasil-Jimi</tabTitle>” with “<selection>@@ -5,84 +5,140 @@5namespace Tests\Unit\Component\ES\Processor\DTOs;5namespace Tests\Unit\Component\ES\Processor\DTOs;667use Jiminny\Component\ES\Processor\DTOs\SelectionList;7use Jiminny\Component\ES\Processor\DTOs\SelectionList;8+use Jiminny\Component\ES\QueuePriorityEnum;8use PHPUnit\Framework\Attributes\CoversClass;9use PHPUnit\Framework\Attributes\CoversClass;9use PHPUnit\Framework\TestCase;10use PHPUnit\Framework\TestCase;101111#[CoversClass(SelectionList::class)]12#[CoversClass(SelectionList::class)]12final class SelectionListTest extends TestCase13final class SelectionListTest extends TestCase13{14{14-public function testGetEntityIds(): void15+private const int CHUNK_SIZE = 100;16+17+public function testAddEntityListAndGetAllIds(): void18+ {19+$selectionList = new SelectionList();20+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);21+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);22+23+$this->assertSame([1, 2, 3, 4], $selectionList->getAllIds());24+ }25+26+public function testAddEntityListMergesMultipleCallsForSamePriority(): void27+ {28+$selectionList = new SelectionList();29+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);30+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [3, 4]);31+32+$this->assertSame([1, 2, 3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));33+ }34+35+public function testGetEntityListItemsByGroup(): void36+ {37+$selectionList = new SelectionList();38+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);39+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);40+$selectionList->addEntityList(QueuePriorityEnum::LOW, [5, 6]);41+42+$this->assertSame([1, 2], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));43+$this->assertSame([3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::NORMAL));44+$this->assertSame([5, 6], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::LOW));45+ }46+47+public function testGetEntityListItemsByGroupReturnsEmptyArrayForUnknownGroup(): void15 {48 {16-$priority = ['p1', 'p2'];49+$selectionList = new SelectionList();17-$normal = ['n1', 'n2'];50+18-$selectionList = new SelectionList($priority, $normal);51+$this->assertSame([], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));52+ }195320-$this->assertSame($priority, $selectionList->getHighPriorityEntityIds());54+public function testGetEntityListGroups(): void21-$this->assertSame($normal, $selectionList->getNormalPriorityEntityId());55+ {56+$selectionList = new SelectionList();57+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);58+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2]);225923-$this->assertSame(['p1', 'p2', 'n1', 'n2'], $selectionList->getAllIds());60+$this->assertSame(['high', 'normal'], $selectionList->getEntityListGroups());24 }61 }256226public function testCountReturnsTotalCount(): void63public function testCountReturnsTotalCount(): void27 {64 {28-$selectionList = new SelectionList(['p1'], ['n1', 'n2']);65+$selectionList = new SelectionList();66+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);67+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2, 3]);68+29$this->assertSame(3, $selectionList->count());69$this->assertSame(3, $selectionList->count());30 }70 }317132-public function testIsEmptyReturnsTrueWhenBothListsAreEmpty(): void72+public function testIsEmptyReturnsTrueWhenNoEntitiesAdded(): void33 {73 {34-$selectionList = new SelectionList([], []);74+$selectionList = new SelectionList();75+35$this->assertTrue($selectionList->isEmpty());76$this->assertTrue($selectionList->isEmpty());36 }77 }377838-public function testIsEmptyReturnsFalseWhenAnyListIsNotEmpty(): void79+public function testIsEmptyReturnsFalseWhenEntitiesAdded(): void39 {80 {40-$selectionList = new SelectionList(['p1'], []);81+$selectionList = new SelectionList();41-$this->assertFalse($selectionList->isEmpty());82+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);428343-$selectionList2 = new SelectionList([], ['n1']);84+$this->assertFalse($selectionList->isEmpty());44-$this->assertFalse($selectionList2->isEmpty());45 }85 }468647-public function testIsStaleChunkSelected(): void87+public function testMarkStaleAndIsStaleChunkSelected(): void48 {88 {49-$selectionList = new SelectionList([], [], true);89+$selectionList = new SelectionList();50-$this->assertTrue($selectionList->isStaleChunkSelected());90+91+$this->assertFalse($selectionList->isStaleChunkSelected());92+93+$selectionList->markStale();519452-$selectionList2 = new SelectionList([], [], false);95+$this->assertTrue($selectionList->isStaleChunkSelected());53-$this->assertFalse($selectionList2->isStaleChunkSelected());54 }96 }559756public function testIsFullChunk(): void98public function testIsFullChunk(): void57 {99 {58-$chunkSize = 200;100+$selectionList = new SelectionList();59-101+$selectionList->setChunkSize(self::CHUNK_SIZE);60-$fullList = range(1, $chunkSize);102+61-$selectionList = new SelectionList(103+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, self::CHUNK_SIZE));62- priorityEntityIdList: $fullList,104+63- normalEntityIdList: [],105+$this->assertTrue($selectionList->isFullChunk());64- chunkSize: $chunkSize,106+ }65- );107+108+public function testIsNotFullChunkWhenBelowChunkSize(): void109+ {110+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);111+112+$selectionList = new SelectionList();113+$selectionList->setChunkSize(self::CHUNK_SIZE);114+115+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range(1, $halfRange));116+117+$this->assertFalse($selectionList->isFullChunk());118+ }119+120+public function testIsFullChunkAcrossMultiplePriorityGroups(): void121+ {122+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);123+124+$selectionList = new SelectionList();125+$selectionList->setChunkSize(self::CHUNK_SIZE);126+127+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, $halfRange));128+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range($halfRange + 1, self::CHUNK_SIZE));129+130+$this->assertTrue($selectionList->isFullChunk());131+ }132+133+public function testSetChunkSizeAffectsIsFullChunk(): void134+ {135+$selectionList = new SelectionList();136+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [1, 2, 3]);137+138+$selectionList->setChunkSize(3);66$this->assertTrue($selectionList->isFullChunk());139$this->assertTrue($selectionList->isFullChunk());6714068-$halfRange = (int) ceil($chunkSize / 2);141+$selectionList->setChunkSize(50);69-142+$this->assertFalse($selectionList->isFullChunk());70-$notFullList = range(1, $halfRange);71-$selectionList2 = new SelectionList(72- priorityEntityIdList: $notFullList,73- normalEntityIdList: [],74- chunkSize: $chunkSize,75- );76-$this->assertFalse($selectionList2->isFullChunk());77-78-$priorityRange = range(1, $halfRange);79-$normalRange = range($halfRange + 1, $chunkSize);80-81-$selectionList3 = new SelectionList(82- priorityEntityIdList: $priorityRange,83- normalEntityIdList: $normalRange,84- chunkSize: $chunkSize,85- );86-$this->assertTrue($selectionList3->isFullChunk());87 }143 }88}144}</selection>” selected. Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
You said
I’m on page “<tabTitle>JY-20808 low priority indexing queue by Vasil-Jimi</tabTitle>” with “<selection>@@ -5,84 +5,140 @@5namespace Tests\Unit\Component\ES\Processor\DTOs;5namespace Tests\Unit\Component\ES\Processor\DTOs;667use Jiminny\Component\ES\Processor\DTOs\SelectionList;7use Jiminny\Component\ES\Processor\DTOs\SelectionList;8+use Jiminny\Component\ES\QueuePriorityEnum;8use PHPUnit\Framework\Attributes\CoversClass;9use PHPUnit\Framework\Attributes\CoversClass;9use PHPUnit\Framework\TestCase;10use PHPUnit\Framework\TestCase;101111#[CoversClass(SelectionList::class)]12#[CoversClass(SelectionList::class)]12final class SelectionListTest extends TestCase13final class SelectionListTest extends TestCase13{14{14-public function testGetEntityIds(): void15+private const int CHUNK_SIZE = 100;16+17+public function testAddEntityListAndGetAllIds(): void18+ {19+$selectionList = new SelectionList();20+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);21+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);22+23+$this->assertSame([1, 2, 3, 4], $selectionList->getAllIds());24+ }25+26+public function testAddEntityListMergesMultipleCallsForSamePriority(): void27+ {28+$selectionList = new SelectionList();29+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);30+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [3, 4]);31+32+$this->assertSame([1, 2, 3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));33+ }34+35+public function testGetEntityListItemsByGroup(): void36+ {37+$selectionList = new SelectionList();38+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);39+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);40+$selectionList->addEntityList(QueuePriorityEnum::LOW, [5, 6]);41+42+$this->assertSame([1, 2], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));43+$this->assertSame([3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::NORMAL));44+$this->assertSame([5, 6], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::LOW));45+ }46+47+public function testGetEntityListItemsByGroupReturnsEmptyArrayForUnknownGroup(): void15 {48 {16-$priority = ['p1', 'p2'];49+$selectionList = new SelectionList();17-$normal = ['n1', 'n2'];50+18-$selectionList = new SelectionList($priority, $normal);51+$this->assertSame([], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));52+ }195320-$this->assertSame($priority, $selectionList->getHighPriorityEntityIds());54+public function testGetEntityListGroups(): void21-$this->assertSame($normal, $selectionList->getNormalPriorityEntityId());55+ {56+$selectionList = new SelectionList();57+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);58+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2]);225923-$this->assertSame(['p1', 'p2', 'n1', 'n2'], $selectionList->getAllIds());60+$this->assertSame(['high', 'normal'], $selectionList->getEntityListGroups());24 }61 }256226public function testCountReturnsTotalCount(): void63public function testCountReturnsTotalCount(): void27 {64 {28-$selectionList = new SelectionList(['p1'], ['n1', 'n2']);65+$selectionList = new SelectionList();66+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);67+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2, 3]);68+29$this->assertSame(3, $selectionList->count());69$this->assertSame(3, $selectionList->count());30 }70 }317132-public function testIsEmptyReturnsTrueWhenBothListsAreEmpty(): void72+public function testIsEmptyReturnsTrueWhenNoEntitiesAdded(): void33 {73 {34-$selectionList = new SelectionList([], []);74+$selectionList = new SelectionList();75+35$this->assertTrue($selectionList->isEmpty());76$this->assertTrue($selectionList->isEmpty());36 }77 }377838-public function testIsEmptyReturnsFalseWhenAnyListIsNotEmpty(): void79+public function testIsEmptyReturnsFalseWhenEntitiesAdded(): void39 {80 {40-$selectionList = new SelectionList(['p1'], []);81+$selectionList = new SelectionList();41-$this->assertFalse($selectionList->isEmpty());82+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);428343-$selectionList2 = new SelectionList([], ['n1']);84+$this->assertFalse($selectionList->isEmpty());44-$this->assertFalse($selectionList2->isEmpty());45 }85 }468647-public function testIsStaleChunkSelected(): void87+public function testMarkStaleAndIsStaleChunkSelected(): void48 {88 {49-$selectionList = new SelectionList([], [], true);89+$selectionList = new SelectionList();50-$this->assertTrue($selectionList->isStaleChunkSelected());90+91+$this->assertFalse($selectionList->isStaleChunkSelected());92+93+$selectionList->markStale();519452-$selectionList2 = new SelectionList([], [], false);95+$this->assertTrue($selectionList->isStaleChunkSelected());53-$this->assertFalse($selectionList2->isStaleChunkSelected());54 }96 }559756public function testIsFullChunk(): void98public function testIsFullChunk(): void57 {99 {58-$chunkSize = 200;100+$selectionList = new SelectionList();59-101+$selectionList->setChunkSize(self::CHUNK_SIZE);60-$fullList = range(1, $chunkSize);102+61-$selectionList = new SelectionList(103+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, self::CHUNK_SIZE));62- priorityEntityIdList: $fullList,104+63- normalEntityIdList: [],105+$this->assertTrue($selectionList->isFullChunk());64- chunkSize: $chunkSize,106+ }65- );107+108+public function testIsNotFullChunkWhenBelowChunkSize(): void109+ {110+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);111+112+$selectionList = new SelectionList();113+$selectionList->setChunkSize(self::CHUNK_SIZE);114+115+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range(1, $halfRange));116+117+$this->assertFalse($selectionList->isFullChunk());118+ }119+120+public function testIsFullChunkAcrossMultiplePriorityGroups(): void121+ {122+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);123+124+$selectionList = new SelectionList();125+$selectionList->setChunkSize(self::CHUNK_SIZE);126+127+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, $halfRange));128+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range($halfRange + 1, self::CHUNK_SIZE));129+130+$this->assertTrue($selectionList->isFullChunk());131+ }132+133+public function testSetChunkSizeAffectsIsFullChunk(): void134+ {135+$selectionList = new SelectionList();136+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [1, 2, 3]);137+138+$selectionList->setChunkSize(3);66$this->assertTrue($selectionList->isFullChunk());139$this->assertTrue($selectionList->isFullChunk());6714068-$halfRange = (int) ceil($chunkSize / 2);141+$selectionList->setChunkSize(50);69-142+$this->assertFalse($selectionList->isFullChunk());70-$notFullList = range(1, $halfRange);71-$selectionList2 = new SelectionList(72- priorityEntityIdList: $notFullList,73- normalEntityIdList: [],74- chunkSize: $chunkSize,75- );76-$this->assertFalse($selectionList2->isFullChunk());77-78-$priorityRange = range(1, $halfRange);79-$normalRange = range($halfRange + 1, $chunkSize);80-81-$selectionList3 = new SelectionList(82- priorityEntityIdList: $priorityRange,83- normalEntityIdList: $normalRange,84- chunkSize: $chunkSize,85- );86-$this->assertTrue($selectionList3->isFullChunk());87 }143 }88}144}</selection>” selected.
Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
Expand
Listen
Gemini said
Gemini said
Here is a precise and concise summary of the code selection, which refactors
SelectionListTest
to accommodate a shift from fixed high/normal priority properties to a more dynamic, enum-driven priority group architecture.
Refactored Priority Handling
Refactored Priority Handling
Dynamic Priority Groups:
Replaces fixed high/normal array parameters with the
QueuePriorityEnum
(
HIGH
,
NORMAL
,
LOW
), allowing entity lists to be managed dynamically by group types.
Merged Registrations:
Validates that multiple
addEntityList()
calls targeting the same priority level properly merge their data instead of overwriting it.
Group Querying:
Tests new methods
getEntityListItemsByGroup()
and
getEntityListGroups()
to retrieve group-specific IDs or an array of active group names (e.g.,
['high', 'normal']
).
Updated State and Count Validations
Updated State and Count Validations
Instantiation:
Tests now instantiate
SelectionList
without initial constructor arguments, using setters and action methods instead.
Empty States:
Updates assertions (
isEmpty()
) to verify state based on whether any entities have been dynamically added, rather than checking pre-defined constructor arrays.
Stale Flags:
Changes from passing a
stale
boolean via the constructor to explicitly triggering a mutable
$selectionList->markStale()
method.
Chunk Capacity Behavior
Chunk Capacity Behavior
Flexible Chunk Sizes:
Introduces a
setChunkSize()
method, replacing the constructor-configured chunk boundary.
Capacity Assertions:
Retains and updates the logic for
isFullChunk()
, ensuring it accurately evaluates capacity when elements span multiple dynamic priority groups or when the chunk limit is altered mid-lifecycle.
Good response
Bad response
Share & export
Copy
Show more options
Copy prompt
You said Are there any issues or potential bolltenecks
You said
Are there any issues or potential bolltenecks
Listen
Show thinking
Gemini said
Gemini said
Based on the test diff you provided, we can infer a few potential issues and architectural bottlenecks in the underlying
SelectionList
implementation. While the tests are well-structured, the behavior they describe hints at a few areas you might want to keep an eye on, particularly for an Elasticsearch (ES) processor queue.
Here are the potential issues and bottlenecks to consider:
1. Array Merging Overhead (Performance)
1. Array Merging Overhead (Performance)
The
testAddEntityListMergesMultipleCallsForSamePriority
test shows that calling
addEntityList()
multiple times for the same priority group merges the arrays.
The Bottleneck:
If the underlying implementation uses
array_merge()
inside a loop to append these IDs, it creates a new array in memory every time it's called. If you are processing thousands of entities and appending them in small batches, this can lead to memory bloat and CPU degradation due to constant array reallocation.
Mitigation:
Ensure the implementation handles batch appends efficiently (e.g., using the spread operator
[...$existing, ...$new]
or appending via references) or groups the arrays before doing a single merge.
2. Lack of Uniqueness/Deduplication (Logic)
2. Lack of Uniqueness/Deduplication (Logic)
None of the tests explicitly verify what happens if duplicate IDs are added. For example, if you call
addEntityList(QueuePriorityEnum::HIGH, [1, 2])
and then
addEntityList(QueuePriorityEnum::HIGH, [2, 3])
.
The Issue:
Does the getter return
[1, 2, 2, 3]
or
[1, 2, 3]
? If duplicates are not filtered out, your ES processor might end up indexing the same entity multiple times in a single chunk, which wastes I/O and processor cycles.
Mitigation:
The underlying class should ideally enforce uniqueness (e.g., using
array_unique()
before resolving the chunk, or using ID keys as associative array keys to naturally prevent duplicates).
3. Memory Consumption with Large Chunks (Scalability)
3. Memory Consumption with Large Chunks (Scalability)
The tests introduce
setChunkSize()
. If this chunk size is configured to be very large (e.g., tens of thousands of IDs to bulk-send to Elasticsearch).
The Bottleneck:
Holding massive arrays of IDs in memory across different priority groups can quickly hit PHP memory limits, especially if this
SelectionList
object is kept alive during a long-running daemon or cron job.
Mitigation:
Monitor memory usage if
CHUNK_SIZE
grows, and ensure the
SelectionList
object is properly destroyed (or garbage collected) after the chunk is processed to free up memory.
4. Type Juggling
4. Type Juggling
In the original code, string IDs were used (
['p1', 'p2']
). In the refactored tests, integer IDs are used (
[1, 2]
).
The Issue:
If your system handles UUIDs (strings) vs. relational DB auto-increments (integers), make sure the underlying implementation uses strict comparisons (
===
) where necessary, especially if deduplicating arrays, to prevent PHP from juggling
'1'
and
1
improperly.
Would you like me to draft a quick test case to check how the class currently handles duplicate IDs, or is deduplication intentionally handled further down your pipeline?
Good response
Bad response
Share & export
Copy
Show more options
Copy prompt
You said what about non test files
You said
what about non test files
Listen
Show thinking
Gemini said
Gemini said
Since we don't have the actual
SelectionList.php
file, we have to reverse-engineer its implementation based on the test behaviors. Moving from a constructor-based, fixed-property model to a dynamic, mutable model introduces several potential pitfalls in the implementation file itself.
Here are the specific bottlenecks and issues to watch out for in the
SelectionList.php
source code:
1. The count() Method Implementation (Performance Trap)
1. The
count()
Method Implementation (Performance Trap)
The Risk:
If
count()
is implemented by calling
$this->getAllIds()
and counting the resulting merged array (e.g.,
return count($this->getAllIds());
), it will be highly inefficient. It would allocate a brand-new array in memory just to determine its length.
The Fix:
count()
should mathematically sum the sizes of the underlying group arrays without merging them:
return array_sum(array_map('count', $this->entityLists));
2. Loss of Immutability (State Management)
2. Loss of Immutability (State Management)
The Risk:
The original code passed all data via the constructor, implying the DTO (Data Transfer Object) was immutable once created. The refactored version introduces mutability (
addEntityList()
,
setChunkSize()
,
markStale()
). DTOs are typically passed between architectural layers; if one layer modifies the chunk size or adds entities while another is processing it, it can cause unpredictable side effects or race conditions in your queue processor.
The Fix:
Ensure that this object is not shared across asynchronous contexts, or consider returning cloned instances when mutating state if strict immutability is required.
3. Enum Array Key Violations (PHP Quirks)
3. Enum Array Key Violations (PHP Quirks)
The Risk:
The tests show
QueuePriorityEnum::HIGH
being passed to methods. If the underlying code attempts to use this Enum directly as an array key (e.g.,
$this->lists[$priority] = $ids;
), PHP will throw an error because objects (including Enums) cannot be used as standard array keys.
The Fix:
The implementation must map the Enum to its underlying scalar value (e.g.,
$this->lists[$priority->value]
) or use PHP's
WeakMap
or
SplObjectStorage
, though standard arrays using
$priority->value
are much faster for simple lists.
4. Uninitialized State Defaults (Logic Errors)
4. Uninitialized State Defaults (Logic Errors)
The Risk:
The tests instantiate
new SelectionList()
without arguments, then later call
$selectionList->setChunkSize(100)
. If
isFullChunk()
is called
before
setChunkSize()
is invoked, what happens?
The Fix:
Ensure
SelectionList
has a sensible default for chunk size (e.g.,
private int $chunkSize = 0;
or a system default) to prevent uninitialized property errors or division-by-zero scenarios if your logic ever relies on chunk math.
5. getAllIds() Repeated Execution (CPU Overhead)
5.
getAllIds()
Repeated Execution (CPU Overhead)
The Risk:
If
getAllIds()
dynamically merges arrays (
array_merge(...$this->lists)
) every time it is invoked, and your ES processor calls this method inside a loop, it will spike CPU usage.
The Fix:
If the list is read frequently, the implementation should either cache the merged result and invalidate that cache when
addEntityList()
is called, or the caller should assign the result to a local variable before iterating.
Would you like me to draft an optimal, memory-efficient skeleton for the
SelectionList.php
implementation that avoids these specific pitfalls?
Good response
Bad response
Share & export
Copy
Show more options...
|
[{"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":"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 I’m on page “<tabTitle>JY-20808 low priority indexing queue by Vasil-Jimi</tabTitle>” with “<selection>@@ -5,84 +5,140 @@5namespace Tests\\Unit\\Component\\ES\\Processor\\DTOs;5namespace Tests\\Unit\\Component\\ES\\Processor\\DTOs;667use Jiminny\\Component\\ES\\Processor\\DTOs\\SelectionList;7use Jiminny\\Component\\ES\\Processor\\DTOs\\SelectionList;8+use Jiminny\\Component\\ES\\QueuePriorityEnum;8use PHPUnit\\Framework\\Attributes\\CoversClass;9use PHPUnit\\Framework\\Attributes\\CoversClass;9use PHPUnit\\Framework\\TestCase;10use PHPUnit\\Framework\\TestCase;101111#[CoversClass(SelectionList::class)]12#[CoversClass(SelectionList::class)]12final class SelectionListTest extends TestCase13final class SelectionListTest extends TestCase13{14{14-public function testGetEntityIds(): void15+private const int CHUNK_SIZE = 100;16+17+public function testAddEntityListAndGetAllIds(): void18+ {19+$selectionList = new SelectionList();20+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);21+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);22+23+$this->assertSame([1, 2, 3, 4], $selectionList->getAllIds());24+ }25+26+public function testAddEntityListMergesMultipleCallsForSamePriority(): void27+ {28+$selectionList = new SelectionList();29+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);30+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [3, 4]);31+32+$this->assertSame([1, 2, 3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));33+ }34+35+public function testGetEntityListItemsByGroup(): void36+ {37+$selectionList = new SelectionList();38+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);39+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);40+$selectionList->addEntityList(QueuePriorityEnum::LOW, [5, 6]);41+42+$this->assertSame([1, 2], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));43+$this->assertSame([3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::NORMAL));44+$this->assertSame([5, 6], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::LOW));45+ }46+47+public function testGetEntityListItemsByGroupReturnsEmptyArrayForUnknownGroup(): void15 {48 {16-$priority = ['p1', 'p2'];49+$selectionList = new SelectionList();17-$normal = ['n1', 'n2'];50+18-$selectionList = new SelectionList($priority, $normal);51+$this->assertSame([], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));52+ }195320-$this->assertSame($priority, $selectionList->getHighPriorityEntityIds());54+public function testGetEntityListGroups(): void21-$this->assertSame($normal, $selectionList->getNormalPriorityEntityId());55+ {56+$selectionList = new SelectionList();57+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);58+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2]);225923-$this->assertSame(['p1', 'p2', 'n1', 'n2'], $selectionList->getAllIds());60+$this->assertSame(['high', 'normal'], $selectionList->getEntityListGroups());24 }61 }256226public function testCountReturnsTotalCount(): void63public function testCountReturnsTotalCount(): void27 {64 {28-$selectionList = new SelectionList(['p1'], ['n1', 'n2']);65+$selectionList = new SelectionList();66+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);67+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2, 3]);68+29$this->assertSame(3, $selectionList->count());69$this->assertSame(3, $selectionList->count());30 }70 }317132-public function testIsEmptyReturnsTrueWhenBothListsAreEmpty(): void72+public function testIsEmptyReturnsTrueWhenNoEntitiesAdded(): void33 {73 {34-$selectionList = new SelectionList([], []);74+$selectionList = new SelectionList();75+35$this->assertTrue($selectionList->isEmpty());76$this->assertTrue($selectionList->isEmpty());36 }77 }377838-public function testIsEmptyReturnsFalseWhenAnyListIsNotEmpty(): void79+public function testIsEmptyReturnsFalseWhenEntitiesAdded(): void39 {80 {40-$selectionList = new SelectionList(['p1'], []);81+$selectionList = new SelectionList();41-$this->assertFalse($selectionList->isEmpty());82+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);428343-$selectionList2 = new SelectionList([], ['n1']);84+$this->assertFalse($selectionList->isEmpty());44-$this->assertFalse($selectionList2->isEmpty());45 }85 }468647-public function testIsStaleChunkSelected(): void87+public function testMarkStaleAndIsStaleChunkSelected(): void48 {88 {49-$selectionList = new SelectionList([], [], true);89+$selectionList = new SelectionList();50-$this->assertTrue($selectionList->isStaleChunkSelected());90+91+$this->assertFalse($selectionList->isStaleChunkSelected());92+93+$selectionList->markStale();519452-$selectionList2 = new SelectionList([], [], false);95+$this->assertTrue($selectionList->isStaleChunkSelected());53-$this->assertFalse($selectionList2->isStaleChunkSelected());54 }96 }559756public function testIsFullChunk(): void98public function testIsFullChunk(): void57 {99 {58-$chunkSize = 200;100+$selectionList = new SelectionList();59-101+$selectionList->setChunkSize(self::CHUNK_SIZE);60-$fullList = range(1, $chunkSize);102+61-$selectionList = new SelectionList(103+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, self::CHUNK_SIZE));62- priorityEntityIdList: $fullList,104+63- normalEntityIdList: [],105+$this->assertTrue($selectionList->isFullChunk());64- chunkSize: $chunkSize,106+ }65- );107+108+public function testIsNotFullChunkWhenBelowChunkSize(): void109+ {110+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);111+112+$selectionList = new SelectionList();113+$selectionList->setChunkSize(self::CHUNK_SIZE);114+115+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range(1, $halfRange));116+117+$this->assertFalse($selectionList->isFullChunk());118+ }119+120+public function testIsFullChunkAcrossMultiplePriorityGroups(): void121+ {122+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);123+124+$selectionList = new SelectionList();125+$selectionList->setChunkSize(self::CHUNK_SIZE);126+127+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, $halfRange));128+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range($halfRange + 1, self::CHUNK_SIZE));129+130+$this->assertTrue($selectionList->isFullChunk());131+ }132+133+public function testSetChunkSizeAffectsIsFullChunk(): void134+ {135+$selectionList = new SelectionList();136+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [1, 2, 3]);137+138+$selectionList->setChunkSize(3);66$this->assertTrue($selectionList->isFullChunk());139$this->assertTrue($selectionList->isFullChunk());6714068-$halfRange = (int) ceil($chunkSize / 2);141+$selectionList->setChunkSize(50);69-142+$this->assertFalse($selectionList->isFullChunk());70-$notFullList = range(1, $halfRange);71-$selectionList2 = new SelectionList(72- priorityEntityIdList: $notFullList,73- normalEntityIdList: [],74- chunkSize: $chunkSize,75- );76-$this->assertFalse($selectionList2->isFullChunk());77-78-$priorityRange = range(1, $halfRange);79-$normalRange = range($halfRange + 1, $chunkSize);80-81-$selectionList3 = new SelectionList(82- priorityEntityIdList: $priorityRange,83- normalEntityIdList: $normalRange,84- chunkSize: $chunkSize,85- );86-$this->assertTrue($selectionList3->isFullChunk());87 }143 }88}144}</selection>” selected. Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.","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":"I’m on page “<tabTitle>JY-20808 low priority indexing queue by Vasil-Jimi</tabTitle>” with “<selection>@@ -5,84 +5,140 @@5namespace Tests\\Unit\\Component\\ES\\Processor\\DTOs;5namespace Tests\\Unit\\Component\\ES\\Processor\\DTOs;667use Jiminny\\Component\\ES\\Processor\\DTOs\\SelectionList;7use Jiminny\\Component\\ES\\Processor\\DTOs\\SelectionList;8+use Jiminny\\Component\\ES\\QueuePriorityEnum;8use PHPUnit\\Framework\\Attributes\\CoversClass;9use PHPUnit\\Framework\\Attributes\\CoversClass;9use PHPUnit\\Framework\\TestCase;10use PHPUnit\\Framework\\TestCase;101111#[CoversClass(SelectionList::class)]12#[CoversClass(SelectionList::class)]12final class SelectionListTest extends TestCase13final class SelectionListTest extends TestCase13{14{14-public function testGetEntityIds(): void15+private const int CHUNK_SIZE = 100;16+17+public function testAddEntityListAndGetAllIds(): void18+ {19+$selectionList = new SelectionList();20+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);21+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);22+23+$this->assertSame([1, 2, 3, 4], $selectionList->getAllIds());24+ }25+26+public function testAddEntityListMergesMultipleCallsForSamePriority(): void27+ {28+$selectionList = new SelectionList();29+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);30+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [3, 4]);31+32+$this->assertSame([1, 2, 3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));33+ }34+35+public function testGetEntityListItemsByGroup(): void36+ {37+$selectionList = new SelectionList();38+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);39+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);40+$selectionList->addEntityList(QueuePriorityEnum::LOW, [5, 6]);41+42+$this->assertSame([1, 2], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));43+$this->assertSame([3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::NORMAL));44+$this->assertSame([5, 6], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::LOW));45+ }46+47+public function testGetEntityListItemsByGroupReturnsEmptyArrayForUnknownGroup(): void15 {48 {16-$priority = ['p1', 'p2'];49+$selectionList = new SelectionList();17-$normal = ['n1', 'n2'];50+18-$selectionList = new SelectionList($priority, $normal);51+$this->assertSame([], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));52+ }195320-$this->assertSame($priority, $selectionList->getHighPriorityEntityIds());54+public function testGetEntityListGroups(): void21-$this->assertSame($normal, $selectionList->getNormalPriorityEntityId());55+ {56+$selectionList = new SelectionList();57+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);58+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2]);225923-$this->assertSame(['p1', 'p2', 'n1', 'n2'], $selectionList->getAllIds());60+$this->assertSame(['high', 'normal'], $selectionList->getEntityListGroups());24 }61 }256226public function testCountReturnsTotalCount(): void63public function testCountReturnsTotalCount(): void27 {64 {28-$selectionList = new SelectionList(['p1'], ['n1', 'n2']);65+$selectionList = new SelectionList();66+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);67+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2, 3]);68+29$this->assertSame(3, $selectionList->count());69$this->assertSame(3, $selectionList->count());30 }70 }317132-public function testIsEmptyReturnsTrueWhenBothListsAreEmpty(): void72+public function testIsEmptyReturnsTrueWhenNoEntitiesAdded(): void33 {73 {34-$selectionList = new SelectionList([], []);74+$selectionList = new SelectionList();75+35$this->assertTrue($selectionList->isEmpty());76$this->assertTrue($selectionList->isEmpty());36 }77 }377838-public function testIsEmptyReturnsFalseWhenAnyListIsNotEmpty(): void79+public function testIsEmptyReturnsFalseWhenEntitiesAdded(): void39 {80 {40-$selectionList = new SelectionList(['p1'], []);81+$selectionList = new SelectionList();41-$this->assertFalse($selectionList->isEmpty());82+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);428343-$selectionList2 = new SelectionList([], ['n1']);84+$this->assertFalse($selectionList->isEmpty());44-$this->assertFalse($selectionList2->isEmpty());45 }85 }468647-public function testIsStaleChunkSelected(): void87+public function testMarkStaleAndIsStaleChunkSelected(): void48 {88 {49-$selectionList = new SelectionList([], [], true);89+$selectionList = new SelectionList();50-$this->assertTrue($selectionList->isStaleChunkSelected());90+91+$this->assertFalse($selectionList->isStaleChunkSelected());92+93+$selectionList->markStale();519452-$selectionList2 = new SelectionList([], [], false);95+$this->assertTrue($selectionList->isStaleChunkSelected());53-$this->assertFalse($selectionList2->isStaleChunkSelected());54 }96 }559756public function testIsFullChunk(): void98public function testIsFullChunk(): void57 {99 {58-$chunkSize = 200;100+$selectionList = new SelectionList();59-101+$selectionList->setChunkSize(self::CHUNK_SIZE);60-$fullList = range(1, $chunkSize);102+61-$selectionList = new SelectionList(103+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, self::CHUNK_SIZE));62- priorityEntityIdList: $fullList,104+63- normalEntityIdList: [],105+$this->assertTrue($selectionList->isFullChunk());64- chunkSize: $chunkSize,106+ }65- );107+108+public function testIsNotFullChunkWhenBelowChunkSize(): void109+ {110+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);111+112+$selectionList = new SelectionList();113+$selectionList->setChunkSize(self::CHUNK_SIZE);114+115+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range(1, $halfRange));116+117+$this->assertFalse($selectionList->isFullChunk());118+ }119+120+public function testIsFullChunkAcrossMultiplePriorityGroups(): void121+ {122+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);123+124+$selectionList = new SelectionList();125+$selectionList->setChunkSize(self::CHUNK_SIZE);126+127+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, $halfRange));128+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range($halfRange + 1, self::CHUNK_SIZE));129+130+$this->assertTrue($selectionList->isFullChunk());131+ }132+133+public function testSetChunkSizeAffectsIsFullChunk(): void134+ {135+$selectionList = new SelectionList();136+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [1, 2, 3]);137+138+$selectionList->setChunkSize(3);66$this->assertTrue($selectionList->isFullChunk());139$this->assertTrue($selectionList->isFullChunk());6714068-$halfRange = (int) ceil($chunkSize / 2);141+$selectionList->setChunkSize(50);69-142+$this->assertFalse($selectionList->isFullChunk());70-$notFullList = range(1, $halfRange);71-$selectionList2 = new SelectionList(72- priorityEntityIdList: $notFullList,73- normalEntityIdList: [],74- chunkSize: $chunkSize,75- );76-$this->assertFalse($selectionList2->isFullChunk());77-78-$priorityRange = range(1, $halfRange);79-$normalRange = range($halfRange + 1, $chunkSize);80-81-$selectionList3 = new SelectionList(82- priorityEntityIdList: $priorityRange,83- normalEntityIdList: $normalRange,84- chunkSize: $chunkSize,85- );86-$this->assertTrue($selectionList3->isFullChunk());87 }143 }88}144}</selection>” selected.","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Expand","depth":21,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"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":"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":"Here is a precise and concise summary of the code selection, which refactors","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SelectionListTest","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"to accommodate a shift from fixed high/normal priority properties to a more dynamic, enum-driven priority group architecture.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Refactored Priority Handling","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Refactored Priority Handling","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Dynamic Priority Groups:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Replaces fixed high/normal array parameters with the","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"QueuePriorityEnum","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"HIGH","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"NORMAL","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"LOW","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"), allowing entity lists to be managed dynamically by group types.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Merged Registrations:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Validates that multiple","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"addEntityList()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"calls targeting the same priority level properly merge their data instead of overwriting it.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Group Querying:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Tests new methods","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"getEntityListItemsByGroup()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"and","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"getEntityListGroups()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"to retrieve group-specific IDs or an array of active group names (e.g.,","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"['high', 'normal']","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":").","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Updated State and Count Validations","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Updated State and Count Validations","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Instantiation:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Tests now instantiate","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SelectionList","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"without initial constructor arguments, using setters and action methods instead.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Empty States:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Updates assertions (","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"isEmpty()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":") to verify state based on whether any entities have been dynamically added, rather than checking pre-defined constructor arrays.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Stale Flags:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Changes from passing a","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"stale","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"boolean via the constructor to explicitly triggering a mutable","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$selectionList->markStale()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"method.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Chunk Capacity Behavior","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Chunk Capacity Behavior","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Flexible Chunk Sizes:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Introduces a","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"setChunkSize()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"method, replacing the constructor-configured chunk boundary.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Capacity Assertions:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Retains and updates the logic for","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"isFullChunk()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":", ensuring it accurately evaluates capacity when elements span multiple dynamic priority groups or when the chunk limit is altered mid-lifecycle.","depth":26,"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":"AXHeading","text":"You said Are there any issues or potential bolltenecks","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":"Are there any issues or potential bolltenecks","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":"Based on the test diff you provided, we can infer a few potential issues and architectural bottlenecks in the underlying","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SelectionList","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"implementation. While the tests are well-structured, the behavior they describe hints at a few areas you might want to keep an eye on, particularly for an Elasticsearch (ES) processor queue.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Here are the potential issues and bottlenecks to consider:","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"1. Array Merging Overhead (Performance)","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1. Array Merging Overhead (Performance)","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"testAddEntityListMergesMultipleCallsForSamePriority","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"test shows that calling","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"addEntityList()","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"multiple times for the same priority group merges the arrays.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The Bottleneck:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"If the underlying implementation uses","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"array_merge()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"inside a loop to append these IDs, it creates a new array in memory every time it's called. If you are processing thousands of entities and appending them in small batches, this can lead to memory bloat and CPU degradation due to constant array reallocation.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Mitigation:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Ensure the implementation handles batch appends efficiently (e.g., using the spread operator","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"[...$existing, ...$new]","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"or appending via references) or groups the arrays before doing a single merge.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"2. Lack of Uniqueness/Deduplication (Logic)","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2. Lack of Uniqueness/Deduplication (Logic)","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"None of the tests explicitly verify what happens if duplicate IDs are added. For example, if you call","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"addEntityList(QueuePriorityEnum::HIGH, [1, 2])","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"and then","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"addEntityList(QueuePriorityEnum::HIGH, [2, 3])","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":".","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The Issue:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Does the getter return","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"[1, 2, 2, 3]","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"or","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"[1, 2, 3]","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"? If duplicates are not filtered out, your ES processor might end up indexing the same entity multiple times in a single chunk, which wastes I/O and processor cycles.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Mitigation:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The underlying class should ideally enforce uniqueness (e.g., using","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"array_unique()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"before resolving the chunk, or using ID keys as associative array keys to naturally prevent duplicates).","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"3. Memory Consumption with Large Chunks (Scalability)","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3. Memory Consumption with Large Chunks (Scalability)","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The tests introduce","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"setChunkSize()","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":". If this chunk size is configured to be very large (e.g., tens of thousands of IDs to bulk-send to Elasticsearch).","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The Bottleneck:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Holding massive arrays of IDs in memory across different priority groups can quickly hit PHP memory limits, especially if this","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SelectionList","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"object is kept alive during a long-running daemon or cron job.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Mitigation:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Monitor memory usage if","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"CHUNK_SIZE","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"grows, and ensure the","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SelectionList","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"object is properly destroyed (or garbage collected) after the chunk is processed to free up memory.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"4. Type Juggling","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"4. Type Juggling","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"In the original code, string IDs were used (","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"['p1', 'p2']","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"). In the refactored tests, integer IDs are used (","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"[1, 2]","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":").","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The Issue:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"If your system handles UUIDs (strings) vs. relational DB auto-increments (integers), make sure the underlying implementation uses strict comparisons (","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"===","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":") where necessary, especially if deduplicating arrays, to prevent PHP from juggling","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"'1'","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"and","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"improperly.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Would you like me to draft a quick test case to check how the class currently handles duplicate IDs, or is deduplication intentionally handled further down your pipeline?","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":"AXHeading","text":"You said what about non test files","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":"what about non test files","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":"Since we don't have the actual","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SelectionList.php","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"file, we have to reverse-engineer its implementation based on the test behaviors. Moving from a constructor-based, fixed-property model to a dynamic, mutable model introduces several potential pitfalls in the implementation file itself.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Here are the specific bottlenecks and issues to watch out for in the","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SelectionList.php","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"source code:","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"1. The count() Method Implementation (Performance Trap)","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1. The","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"count()","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Method Implementation (Performance Trap)","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The Risk:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"If","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"count()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"is implemented by calling","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$this->getAllIds()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"and counting the resulting merged array (e.g.,","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"return count($this->getAllIds());","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"), it will be highly inefficient. It would allocate a brand-new array in memory just to determine its length.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The Fix:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"count()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"should mathematically sum the sizes of the underlying group arrays without merging them:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"return array_sum(array_map('count', $this->entityLists));","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"2. Loss of Immutability (State Management)","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2. Loss of Immutability (State Management)","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The Risk:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The original code passed all data via the constructor, implying the DTO (Data Transfer Object) was immutable once created. The refactored version introduces mutability (","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"addEntityList()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"setChunkSize()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"markStale()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"). DTOs are typically passed between architectural layers; if one layer modifies the chunk size or adds entities while another is processing it, it can cause unpredictable side effects or race conditions in your queue processor.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The Fix:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Ensure that this object is not shared across asynchronous contexts, or consider returning cloned instances when mutating state if strict immutability is required.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"3. Enum Array Key Violations (PHP Quirks)","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3. Enum Array Key Violations (PHP Quirks)","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The Risk:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The tests show","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"QueuePriorityEnum::HIGH","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"being passed to methods. If the underlying code attempts to use this Enum directly as an array key (e.g.,","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$this->lists[$priority] = $ids;","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"), PHP will throw an error because objects (including Enums) cannot be used as standard array keys.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The Fix:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The implementation must map the Enum to its underlying scalar value (e.g.,","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$this->lists[$priority->value]","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":") or use PHP's","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"WeakMap","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"or","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SplObjectStorage","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":", though standard arrays using","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$priority->value","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"are much faster for simple lists.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"4. Uninitialized State Defaults (Logic Errors)","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"4. Uninitialized State Defaults (Logic Errors)","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The Risk:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The tests instantiate","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"new SelectionList()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"without arguments, then later call","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$selectionList->setChunkSize(100)","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":". If","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"isFullChunk()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"is called","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"before","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"setChunkSize()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"is invoked, what happens?","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The Fix:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Ensure","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SelectionList","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"has a sensible default for chunk size (e.g.,","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private int $chunkSize = 0;","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"or a system default) to prevent uninitialized property errors or division-by-zero scenarios if your logic ever relies on chunk math.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"5. getAllIds() Repeated Execution (CPU Overhead)","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"5.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"getAllIds()","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Repeated Execution (CPU Overhead)","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The Risk:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"If","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"getAllIds()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"dynamically merges arrays (","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"array_merge(...$this->lists)","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":") every time it is invoked, and your ES processor calls this method inside a loop, it will spike CPU usage.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The Fix:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"If the list is read frequently, the implementation should either cache the merged result and invalidate that cache when","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"addEntityList()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"is called, or the caller should assign the result to a local variable before iterating.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Would you like me to draft an optimal, memory-efficient skeleton for the","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SelectionList.php","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"implementation that avoids these specific pitfalls?","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}]...
|
38523222066746791
|
5896451135607762965
|
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
Copy prompt
You said I’m on page “<tabTitle>JY-20808 low priority indexing queue by Vasil-Jimi</tabTitle>” with “<selection>@@ -5,84 +5,140 @@5namespace Tests\Unit\Component\ES\Processor\DTOs;5namespace Tests\Unit\Component\ES\Processor\DTOs;667use Jiminny\Component\ES\Processor\DTOs\SelectionList;7use Jiminny\Component\ES\Processor\DTOs\SelectionList;8+use Jiminny\Component\ES\QueuePriorityEnum;8use PHPUnit\Framework\Attributes\CoversClass;9use PHPUnit\Framework\Attributes\CoversClass;9use PHPUnit\Framework\TestCase;10use PHPUnit\Framework\TestCase;101111#[CoversClass(SelectionList::class)]12#[CoversClass(SelectionList::class)]12final class SelectionListTest extends TestCase13final class SelectionListTest extends TestCase13{14{14-public function testGetEntityIds(): void15+private const int CHUNK_SIZE = 100;16+17+public function testAddEntityListAndGetAllIds(): void18+ {19+$selectionList = new SelectionList();20+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);21+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);22+23+$this->assertSame([1, 2, 3, 4], $selectionList->getAllIds());24+ }25+26+public function testAddEntityListMergesMultipleCallsForSamePriority(): void27+ {28+$selectionList = new SelectionList();29+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);30+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [3, 4]);31+32+$this->assertSame([1, 2, 3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));33+ }34+35+public function testGetEntityListItemsByGroup(): void36+ {37+$selectionList = new SelectionList();38+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);39+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);40+$selectionList->addEntityList(QueuePriorityEnum::LOW, [5, 6]);41+42+$this->assertSame([1, 2], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));43+$this->assertSame([3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::NORMAL));44+$this->assertSame([5, 6], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::LOW));45+ }46+47+public function testGetEntityListItemsByGroupReturnsEmptyArrayForUnknownGroup(): void15 {48 {16-$priority = ['p1', 'p2'];49+$selectionList = new SelectionList();17-$normal = ['n1', 'n2'];50+18-$selectionList = new SelectionList($priority, $normal);51+$this->assertSame([], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));52+ }195320-$this->assertSame($priority, $selectionList->getHighPriorityEntityIds());54+public function testGetEntityListGroups(): void21-$this->assertSame($normal, $selectionList->getNormalPriorityEntityId());55+ {56+$selectionList = new SelectionList();57+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);58+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2]);225923-$this->assertSame(['p1', 'p2', 'n1', 'n2'], $selectionList->getAllIds());60+$this->assertSame(['high', 'normal'], $selectionList->getEntityListGroups());24 }61 }256226public function testCountReturnsTotalCount(): void63public function testCountReturnsTotalCount(): void27 {64 {28-$selectionList = new SelectionList(['p1'], ['n1', 'n2']);65+$selectionList = new SelectionList();66+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);67+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2, 3]);68+29$this->assertSame(3, $selectionList->count());69$this->assertSame(3, $selectionList->count());30 }70 }317132-public function testIsEmptyReturnsTrueWhenBothListsAreEmpty(): void72+public function testIsEmptyReturnsTrueWhenNoEntitiesAdded(): void33 {73 {34-$selectionList = new SelectionList([], []);74+$selectionList = new SelectionList();75+35$this->assertTrue($selectionList->isEmpty());76$this->assertTrue($selectionList->isEmpty());36 }77 }377838-public function testIsEmptyReturnsFalseWhenAnyListIsNotEmpty(): void79+public function testIsEmptyReturnsFalseWhenEntitiesAdded(): void39 {80 {40-$selectionList = new SelectionList(['p1'], []);81+$selectionList = new SelectionList();41-$this->assertFalse($selectionList->isEmpty());82+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);428343-$selectionList2 = new SelectionList([], ['n1']);84+$this->assertFalse($selectionList->isEmpty());44-$this->assertFalse($selectionList2->isEmpty());45 }85 }468647-public function testIsStaleChunkSelected(): void87+public function testMarkStaleAndIsStaleChunkSelected(): void48 {88 {49-$selectionList = new SelectionList([], [], true);89+$selectionList = new SelectionList();50-$this->assertTrue($selectionList->isStaleChunkSelected());90+91+$this->assertFalse($selectionList->isStaleChunkSelected());92+93+$selectionList->markStale();519452-$selectionList2 = new SelectionList([], [], false);95+$this->assertTrue($selectionList->isStaleChunkSelected());53-$this->assertFalse($selectionList2->isStaleChunkSelected());54 }96 }559756public function testIsFullChunk(): void98public function testIsFullChunk(): void57 {99 {58-$chunkSize = 200;100+$selectionList = new SelectionList();59-101+$selectionList->setChunkSize(self::CHUNK_SIZE);60-$fullList = range(1, $chunkSize);102+61-$selectionList = new SelectionList(103+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, self::CHUNK_SIZE));62- priorityEntityIdList: $fullList,104+63- normalEntityIdList: [],105+$this->assertTrue($selectionList->isFullChunk());64- chunkSize: $chunkSize,106+ }65- );107+108+public function testIsNotFullChunkWhenBelowChunkSize(): void109+ {110+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);111+112+$selectionList = new SelectionList();113+$selectionList->setChunkSize(self::CHUNK_SIZE);114+115+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range(1, $halfRange));116+117+$this->assertFalse($selectionList->isFullChunk());118+ }119+120+public function testIsFullChunkAcrossMultiplePriorityGroups(): void121+ {122+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);123+124+$selectionList = new SelectionList();125+$selectionList->setChunkSize(self::CHUNK_SIZE);126+127+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, $halfRange));128+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range($halfRange + 1, self::CHUNK_SIZE));129+130+$this->assertTrue($selectionList->isFullChunk());131+ }132+133+public function testSetChunkSizeAffectsIsFullChunk(): void134+ {135+$selectionList = new SelectionList();136+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [1, 2, 3]);137+138+$selectionList->setChunkSize(3);66$this->assertTrue($selectionList->isFullChunk());139$this->assertTrue($selectionList->isFullChunk());6714068-$halfRange = (int) ceil($chunkSize / 2);141+$selectionList->setChunkSize(50);69-142+$this->assertFalse($selectionList->isFullChunk());70-$notFullList = range(1, $halfRange);71-$selectionList2 = new SelectionList(72- priorityEntityIdList: $notFullList,73- normalEntityIdList: [],74- chunkSize: $chunkSize,75- );76-$this->assertFalse($selectionList2->isFullChunk());77-78-$priorityRange = range(1, $halfRange);79-$normalRange = range($halfRange + 1, $chunkSize);80-81-$selectionList3 = new SelectionList(82- priorityEntityIdList: $priorityRange,83- normalEntityIdList: $normalRange,84- chunkSize: $chunkSize,85- );86-$this->assertTrue($selectionList3->isFullChunk());87 }143 }88}144}</selection>” selected. Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
You said
I’m on page “<tabTitle>JY-20808 low priority indexing queue by Vasil-Jimi</tabTitle>” with “<selection>@@ -5,84 +5,140 @@5namespace Tests\Unit\Component\ES\Processor\DTOs;5namespace Tests\Unit\Component\ES\Processor\DTOs;667use Jiminny\Component\ES\Processor\DTOs\SelectionList;7use Jiminny\Component\ES\Processor\DTOs\SelectionList;8+use Jiminny\Component\ES\QueuePriorityEnum;8use PHPUnit\Framework\Attributes\CoversClass;9use PHPUnit\Framework\Attributes\CoversClass;9use PHPUnit\Framework\TestCase;10use PHPUnit\Framework\TestCase;101111#[CoversClass(SelectionList::class)]12#[CoversClass(SelectionList::class)]12final class SelectionListTest extends TestCase13final class SelectionListTest extends TestCase13{14{14-public function testGetEntityIds(): void15+private const int CHUNK_SIZE = 100;16+17+public function testAddEntityListAndGetAllIds(): void18+ {19+$selectionList = new SelectionList();20+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);21+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);22+23+$this->assertSame([1, 2, 3, 4], $selectionList->getAllIds());24+ }25+26+public function testAddEntityListMergesMultipleCallsForSamePriority(): void27+ {28+$selectionList = new SelectionList();29+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);30+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [3, 4]);31+32+$this->assertSame([1, 2, 3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));33+ }34+35+public function testGetEntityListItemsByGroup(): void36+ {37+$selectionList = new SelectionList();38+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);39+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);40+$selectionList->addEntityList(QueuePriorityEnum::LOW, [5, 6]);41+42+$this->assertSame([1, 2], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));43+$this->assertSame([3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::NORMAL));44+$this->assertSame([5, 6], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::LOW));45+ }46+47+public function testGetEntityListItemsByGroupReturnsEmptyArrayForUnknownGroup(): void15 {48 {16-$priority = ['p1', 'p2'];49+$selectionList = new SelectionList();17-$normal = ['n1', 'n2'];50+18-$selectionList = new SelectionList($priority, $normal);51+$this->assertSame([], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));52+ }195320-$this->assertSame($priority, $selectionList->getHighPriorityEntityIds());54+public function testGetEntityListGroups(): void21-$this->assertSame($normal, $selectionList->getNormalPriorityEntityId());55+ {56+$selectionList = new SelectionList();57+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);58+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2]);225923-$this->assertSame(['p1', 'p2', 'n1', 'n2'], $selectionList->getAllIds());60+$this->assertSame(['high', 'normal'], $selectionList->getEntityListGroups());24 }61 }256226public function testCountReturnsTotalCount(): void63public function testCountReturnsTotalCount(): void27 {64 {28-$selectionList = new SelectionList(['p1'], ['n1', 'n2']);65+$selectionList = new SelectionList();66+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);67+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2, 3]);68+29$this->assertSame(3, $selectionList->count());69$this->assertSame(3, $selectionList->count());30 }70 }317132-public function testIsEmptyReturnsTrueWhenBothListsAreEmpty(): void72+public function testIsEmptyReturnsTrueWhenNoEntitiesAdded(): void33 {73 {34-$selectionList = new SelectionList([], []);74+$selectionList = new SelectionList();75+35$this->assertTrue($selectionList->isEmpty());76$this->assertTrue($selectionList->isEmpty());36 }77 }377838-public function testIsEmptyReturnsFalseWhenAnyListIsNotEmpty(): void79+public function testIsEmptyReturnsFalseWhenEntitiesAdded(): void39 {80 {40-$selectionList = new SelectionList(['p1'], []);81+$selectionList = new SelectionList();41-$this->assertFalse($selectionList->isEmpty());82+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);428343-$selectionList2 = new SelectionList([], ['n1']);84+$this->assertFalse($selectionList->isEmpty());44-$this->assertFalse($selectionList2->isEmpty());45 }85 }468647-public function testIsStaleChunkSelected(): void87+public function testMarkStaleAndIsStaleChunkSelected(): void48 {88 {49-$selectionList = new SelectionList([], [], true);89+$selectionList = new SelectionList();50-$this->assertTrue($selectionList->isStaleChunkSelected());90+91+$this->assertFalse($selectionList->isStaleChunkSelected());92+93+$selectionList->markStale();519452-$selectionList2 = new SelectionList([], [], false);95+$this->assertTrue($selectionList->isStaleChunkSelected());53-$this->assertFalse($selectionList2->isStaleChunkSelected());54 }96 }559756public function testIsFullChunk(): void98public function testIsFullChunk(): void57 {99 {58-$chunkSize = 200;100+$selectionList = new SelectionList();59-101+$selectionList->setChunkSize(self::CHUNK_SIZE);60-$fullList = range(1, $chunkSize);102+61-$selectionList = new SelectionList(103+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, self::CHUNK_SIZE));62- priorityEntityIdList: $fullList,104+63- normalEntityIdList: [],105+$this->assertTrue($selectionList->isFullChunk());64- chunkSize: $chunkSize,106+ }65- );107+108+public function testIsNotFullChunkWhenBelowChunkSize(): void109+ {110+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);111+112+$selectionList = new SelectionList();113+$selectionList->setChunkSize(self::CHUNK_SIZE);114+115+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range(1, $halfRange));116+117+$this->assertFalse($selectionList->isFullChunk());118+ }119+120+public function testIsFullChunkAcrossMultiplePriorityGroups(): void121+ {122+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);123+124+$selectionList = new SelectionList();125+$selectionList->setChunkSize(self::CHUNK_SIZE);126+127+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, $halfRange));128+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range($halfRange + 1, self::CHUNK_SIZE));129+130+$this->assertTrue($selectionList->isFullChunk());131+ }132+133+public function testSetChunkSizeAffectsIsFullChunk(): void134+ {135+$selectionList = new SelectionList();136+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [1, 2, 3]);137+138+$selectionList->setChunkSize(3);66$this->assertTrue($selectionList->isFullChunk());139$this->assertTrue($selectionList->isFullChunk());6714068-$halfRange = (int) ceil($chunkSize / 2);141+$selectionList->setChunkSize(50);69-142+$this->assertFalse($selectionList->isFullChunk());70-$notFullList = range(1, $halfRange);71-$selectionList2 = new SelectionList(72- priorityEntityIdList: $notFullList,73- normalEntityIdList: [],74- chunkSize: $chunkSize,75- );76-$this->assertFalse($selectionList2->isFullChunk());77-78-$priorityRange = range(1, $halfRange);79-$normalRange = range($halfRange + 1, $chunkSize);80-81-$selectionList3 = new SelectionList(82- priorityEntityIdList: $priorityRange,83- normalEntityIdList: $normalRange,84- chunkSize: $chunkSize,85- );86-$this->assertTrue($selectionList3->isFullChunk());87 }143 }88}144}</selection>” selected.
Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
Expand
Listen
Gemini said
Gemini said
Here is a precise and concise summary of the code selection, which refactors
SelectionListTest
to accommodate a shift from fixed high/normal priority properties to a more dynamic, enum-driven priority group architecture.
Refactored Priority Handling
Refactored Priority Handling
Dynamic Priority Groups:
Replaces fixed high/normal array parameters with the
QueuePriorityEnum
(
HIGH
,
NORMAL
,
LOW
), allowing entity lists to be managed dynamically by group types.
Merged Registrations:
Validates that multiple
addEntityList()
calls targeting the same priority level properly merge their data instead of overwriting it.
Group Querying:
Tests new methods
getEntityListItemsByGroup()
and
getEntityListGroups()
to retrieve group-specific IDs or an array of active group names (e.g.,
['high', 'normal']
).
Updated State and Count Validations
Updated State and Count Validations
Instantiation:
Tests now instantiate
SelectionList
without initial constructor arguments, using setters and action methods instead.
Empty States:
Updates assertions (
isEmpty()
) to verify state based on whether any entities have been dynamically added, rather than checking pre-defined constructor arrays.
Stale Flags:
Changes from passing a
stale
boolean via the constructor to explicitly triggering a mutable
$selectionList->markStale()
method.
Chunk Capacity Behavior
Chunk Capacity Behavior
Flexible Chunk Sizes:
Introduces a
setChunkSize()
method, replacing the constructor-configured chunk boundary.
Capacity Assertions:
Retains and updates the logic for
isFullChunk()
, ensuring it accurately evaluates capacity when elements span multiple dynamic priority groups or when the chunk limit is altered mid-lifecycle.
Good response
Bad response
Share & export
Copy
Show more options
Copy prompt
You said Are there any issues or potential bolltenecks
You said
Are there any issues or potential bolltenecks
Listen
Show thinking
Gemini said
Gemini said
Based on the test diff you provided, we can infer a few potential issues and architectural bottlenecks in the underlying
SelectionList
implementation. While the tests are well-structured, the behavior they describe hints at a few areas you might want to keep an eye on, particularly for an Elasticsearch (ES) processor queue.
Here are the potential issues and bottlenecks to consider:
1. Array Merging Overhead (Performance)
1. Array Merging Overhead (Performance)
The
testAddEntityListMergesMultipleCallsForSamePriority
test shows that calling
addEntityList()
multiple times for the same priority group merges the arrays.
The Bottleneck:
If the underlying implementation uses
array_merge()
inside a loop to append these IDs, it creates a new array in memory every time it's called. If you are processing thousands of entities and appending them in small batches, this can lead to memory bloat and CPU degradation due to constant array reallocation.
Mitigation:
Ensure the implementation handles batch appends efficiently (e.g., using the spread operator
[...$existing, ...$new]
or appending via references) or groups the arrays before doing a single merge.
2. Lack of Uniqueness/Deduplication (Logic)
2. Lack of Uniqueness/Deduplication (Logic)
None of the tests explicitly verify what happens if duplicate IDs are added. For example, if you call
addEntityList(QueuePriorityEnum::HIGH, [1, 2])
and then
addEntityList(QueuePriorityEnum::HIGH, [2, 3])
.
The Issue:
Does the getter return
[1, 2, 2, 3]
or
[1, 2, 3]
? If duplicates are not filtered out, your ES processor might end up indexing the same entity multiple times in a single chunk, which wastes I/O and processor cycles.
Mitigation:
The underlying class should ideally enforce uniqueness (e.g., using
array_unique()
before resolving the chunk, or using ID keys as associative array keys to naturally prevent duplicates).
3. Memory Consumption with Large Chunks (Scalability)
3. Memory Consumption with Large Chunks (Scalability)
The tests introduce
setChunkSize()
. If this chunk size is configured to be very large (e.g., tens of thousands of IDs to bulk-send to Elasticsearch).
The Bottleneck:
Holding massive arrays of IDs in memory across different priority groups can quickly hit PHP memory limits, especially if this
SelectionList
object is kept alive during a long-running daemon or cron job.
Mitigation:
Monitor memory usage if
CHUNK_SIZE
grows, and ensure the
SelectionList
object is properly destroyed (or garbage collected) after the chunk is processed to free up memory.
4. Type Juggling
4. Type Juggling
In the original code, string IDs were used (
['p1', 'p2']
). In the refactored tests, integer IDs are used (
[1, 2]
).
The Issue:
If your system handles UUIDs (strings) vs. relational DB auto-increments (integers), make sure the underlying implementation uses strict comparisons (
===
) where necessary, especially if deduplicating arrays, to prevent PHP from juggling
'1'
and
1
improperly.
Would you like me to draft a quick test case to check how the class currently handles duplicate IDs, or is deduplication intentionally handled further down your pipeline?
Good response
Bad response
Share & export
Copy
Show more options
Copy prompt
You said what about non test files
You said
what about non test files
Listen
Show thinking
Gemini said
Gemini said
Since we don't have the actual
SelectionList.php
file, we have to reverse-engineer its implementation based on the test behaviors. Moving from a constructor-based, fixed-property model to a dynamic, mutable model introduces several potential pitfalls in the implementation file itself.
Here are the specific bottlenecks and issues to watch out for in the
SelectionList.php
source code:
1. The count() Method Implementation (Performance Trap)
1. The
count()
Method Implementation (Performance Trap)
The Risk:
If
count()
is implemented by calling
$this->getAllIds()
and counting the resulting merged array (e.g.,
return count($this->getAllIds());
), it will be highly inefficient. It would allocate a brand-new array in memory just to determine its length.
The Fix:
count()
should mathematically sum the sizes of the underlying group arrays without merging them:
return array_sum(array_map('count', $this->entityLists));
2. Loss of Immutability (State Management)
2. Loss of Immutability (State Management)
The Risk:
The original code passed all data via the constructor, implying the DTO (Data Transfer Object) was immutable once created. The refactored version introduces mutability (
addEntityList()
,
setChunkSize()
,
markStale()
). DTOs are typically passed between architectural layers; if one layer modifies the chunk size or adds entities while another is processing it, it can cause unpredictable side effects or race conditions in your queue processor.
The Fix:
Ensure that this object is not shared across asynchronous contexts, or consider returning cloned instances when mutating state if strict immutability is required.
3. Enum Array Key Violations (PHP Quirks)
3. Enum Array Key Violations (PHP Quirks)
The Risk:
The tests show
QueuePriorityEnum::HIGH
being passed to methods. If the underlying code attempts to use this Enum directly as an array key (e.g.,
$this->lists[$priority] = $ids;
), PHP will throw an error because objects (including Enums) cannot be used as standard array keys.
The Fix:
The implementation must map the Enum to its underlying scalar value (e.g.,
$this->lists[$priority->value]
) or use PHP's
WeakMap
or
SplObjectStorage
, though standard arrays using
$priority->value
are much faster for simple lists.
4. Uninitialized State Defaults (Logic Errors)
4. Uninitialized State Defaults (Logic Errors)
The Risk:
The tests instantiate
new SelectionList()
without arguments, then later call
$selectionList->setChunkSize(100)
. If
isFullChunk()
is called
before
setChunkSize()
is invoked, what happens?
The Fix:
Ensure
SelectionList
has a sensible default for chunk size (e.g.,
private int $chunkSize = 0;
or a system default) to prevent uninitialized property errors or division-by-zero scenarios if your logic ever relies on chunk math.
5. getAllIds() Repeated Execution (CPU Overhead)
5.
getAllIds()
Repeated Execution (CPU Overhead)
The Risk:
If
getAllIds()
dynamically merges arrays (
array_merge(...$this->lists)
) every time it is invoked, and your ES processor calls this method inside a loop, it will spike CPU usage.
The Fix:
If the list is read frequently, the implementation should either cache the merged result and invalidate that cache when
addEntityList()
is called, or the caller should assign the result to a local variable before iterating.
Would you like me to draft an optimal, memory-efficient skeleton for the
SelectionList.php
implementation that avoids these specific pitfalls?
Good response
Bad response
Share & export
Copy
Show more options...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
55658
|
1931
|
19
|
2026-05-19T06:36:17.183610+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779172577183_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-4bd github.com/jiminny/app/pull/12082/changes#diff-4bdd02759b5e0d060dcbc8c2dcb9bdbc3d0266d9c2e29956b9d63916dae1fdd7...
|
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
Copy prompt
You said I’m on page “<tabTitle>JY-20808 low priority indexing queue by Vasil-Jimi</tabTitle>” with “<selection>@@ -5,84 +5,140 @@5namespace Tests\Unit\Component\ES\Processor\DTOs;5namespace Tests\Unit\Component\ES\Processor\DTOs;667use Jiminny\Component\ES\Processor\DTOs\SelectionList;7use Jiminny\Component\ES\Processor\DTOs\SelectionList;8+use Jiminny\Component\ES\QueuePriorityEnum;8use PHPUnit\Framework\Attributes\CoversClass;9use PHPUnit\Framework\Attributes\CoversClass;9use PHPUnit\Framework\TestCase;10use PHPUnit\Framework\TestCase;101111#[CoversClass(SelectionList::class)]12#[CoversClass(SelectionList::class)]12final class SelectionListTest extends TestCase13final class SelectionListTest extends TestCase13{14{14-public function testGetEntityIds(): void15+private const int CHUNK_SIZE = 100;16+17+public function testAddEntityListAndGetAllIds(): void18+ {19+$selectionList = new SelectionList();20+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);21+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);22+23+$this->assertSame([1, 2, 3, 4], $selectionList->getAllIds());24+ }25+26+public function testAddEntityListMergesMultipleCallsForSamePriority(): void27+ {28+$selectionList = new SelectionList();29+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);30+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [3, 4]);31+32+$this->assertSame([1, 2, 3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));33+ }34+35+public function testGetEntityListItemsByGroup(): void36+ {37+$selectionList = new SelectionList();38+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);39+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);40+$selectionList->addEntityList(QueuePriorityEnum::LOW, [5, 6]);41+42+$this->assertSame([1, 2], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));43+$this->assertSame([3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::NORMAL));44+$this->assertSame([5, 6], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::LOW));45+ }46+47+public function testGetEntityListItemsByGroupReturnsEmptyArrayForUnknownGroup(): void15 {48 {16-$priority = ['p1', 'p2'];49+$selectionList = new SelectionList();17-$normal = ['n1', 'n2'];50+18-$selectionList = new SelectionList($priority, $normal);51+$this->assertSame([], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));52+ }195320-$this->assertSame($priority, $selectionList->getHighPriorityEntityIds());54+public function testGetEntityListGroups(): void21-$this->assertSame($normal, $selectionList->getNormalPriorityEntityId());55+ {56+$selectionList = new SelectionList();57+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);58+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2]);225923-$this->assertSame(['p1', 'p2', 'n1', 'n2'], $selectionList->getAllIds());60+$this->assertSame(['high', 'normal'], $selectionList->getEntityListGroups());24 }61 }256226public function testCountReturnsTotalCount(): void63public function testCountReturnsTotalCount(): void27 {64 {28-$selectionList = new SelectionList(['p1'], ['n1', 'n2']);65+$selectionList = new SelectionList();66+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);67+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2, 3]);68+29$this->assertSame(3, $selectionList->count());69$this->assertSame(3, $selectionList->count());30 }70 }317132-public function testIsEmptyReturnsTrueWhenBothListsAreEmpty(): void72+public function testIsEmptyReturnsTrueWhenNoEntitiesAdded(): void33 {73 {34-$selectionList = new SelectionList([], []);74+$selectionList = new SelectionList();75+35$this->assertTrue($selectionList->isEmpty());76$this->assertTrue($selectionList->isEmpty());36 }77 }377838-public function testIsEmptyReturnsFalseWhenAnyListIsNotEmpty(): void79+public function testIsEmptyReturnsFalseWhenEntitiesAdded(): void39 {80 {40-$selectionList = new SelectionList(['p1'], []);81+$selectionList = new SelectionList();41-$this->assertFalse($selectionList->isEmpty());82+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);428343-$selectionList2 = new SelectionList([], ['n1']);84+$this->assertFalse($selectionList->isEmpty());44-$this->assertFalse($selectionList2->isEmpty());45 }85 }468647-public function testIsStaleChunkSelected(): void87+public function testMarkStaleAndIsStaleChunkSelected(): void48 {88 {49-$selectionList = new SelectionList([], [], true);89+$selectionList = new SelectionList();50-$this->assertTrue($selectionList->isStaleChunkSelected());90+91+$this->assertFalse($selectionList->isStaleChunkSelected());92+93+$selectionList->markStale();519452-$selectionList2 = new SelectionList([], [], false);95+$this->assertTrue($selectionList->isStaleChunkSelected());53-$this->assertFalse($selectionList2->isStaleChunkSelected());54 }96 }559756public function testIsFullChunk(): void98public function testIsFullChunk(): void57 {99 {58-$chunkSize = 200;100+$selectionList = new SelectionList();59-101+$selectionList->setChunkSize(self::CHUNK_SIZE);60-$fullList = range(1, $chunkSize);102+61-$selectionList = new SelectionList(103+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, self::CHUNK_SIZE));62- priorityEntityIdList: $fullList,104+63- normalEntityIdList: [],105+$this->assertTrue($selectionList->isFullChunk());64- chunkSize: $chunkSize,106+ }65- );107+108+public function testIsNotFullChunkWhenBelowChunkSize(): void109+ {110+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);111+112+$selectionList = new SelectionList();113+$selectionList->setChunkSize(self::CHUNK_SIZE);114+115+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range(1, $halfRange));116+117+$this->assertFalse($selectionList->isFullChunk());118+ }119+120+public function testIsFullChunkAcrossMultiplePriorityGroups(): void121+ {122+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);123+124+$selectionList = new SelectionList();125+$selectionList->setChunkSize(self::CHUNK_SIZE);126+127+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, $halfRange));128+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range($halfRange + 1, self::CHUNK_SIZE));129+130+$this->assertTrue($selectionList->isFullChunk());131+ }132+133+public function testSetChunkSizeAffectsIsFullChunk(): void134+ {135+$selectionList = new SelectionList();136+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [1, 2, 3]);137+138+$selectionList->setChunkSize(3);66$this->assertTrue($selectionList->isFullChunk());139$this->assertTrue($selectionList->isFullChunk());6714068-$halfRange = (int) ceil($chunkSize / 2);141+$selectionList->setChunkSize(50);69-142+$this->assertFalse($selectionList->isFullChunk());70-$notFullList = range(1, $halfRange);71-$selectionList2 = new SelectionList(72- priorityEntityIdList: $notFullList,73- normalEntityIdList: [],74- chunkSize: $chunkSize,75- );76-$this->assertFalse($selectionList2->isFullChunk());77-78-$priorityRange = range(1, $halfRange);79-$normalRange = range($halfRange + 1, $chunkSize);80-81-$selectionList3 = new SelectionList(82- priorityEntityIdList: $priorityRange,83- normalEntityIdList: $normalRange,84- chunkSize: $chunkSize,85- );86-$this->assertTrue($selectionList3->isFullChunk());87 }143 }88}144}</selection>” selected. Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
You said
I’m on page “<tabTitle>JY-20808 low priority indexing queue by Vasil-Jimi</tabTitle>” with “<selection>@@ -5,84 +5,140 @@5namespace Tests\Unit\Component\ES\Processor\DTOs;5namespace Tests\Unit\Component\ES\Processor\DTOs;667use Jiminny\Component\ES\Processor\DTOs\SelectionList;7use Jiminny\Component\ES\Processor\DTOs\SelectionList;8+use Jiminny\Component\ES\QueuePriorityEnum;8use PHPUnit\Framework\Attributes\CoversClass;9use PHPUnit\Framework\Attributes\CoversClass;9use PHPUnit\Framework\TestCase;10use PHPUnit\Framework\TestCase;101111#[CoversClass(SelectionList::class)]12#[CoversClass(SelectionList::class)]12final class SelectionListTest extends TestCase13final class SelectionListTest extends TestCase13{14{14-public function testGetEntityIds(): void15+private const int CHUNK_SIZE = 100;16+17+public function testAddEntityListAndGetAllIds(): void18+ {19+$selectionList = new SelectionList();20+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);21+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);22+23+$this->assertSame([1, 2, 3, 4], $selectionList->getAllIds());24+ }25+26+public function testAddEntityListMergesMultipleCallsForSamePriority(): void27+ {28+$selectionList = new SelectionList();29+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);30+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [3, 4]);31+32+$this->assertSame([1, 2, 3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));33+ }34+35+public function testGetEntityListItemsByGroup(): void36+ {37+$selectionList = new SelectionList();38+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);39+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);40+$selectionList->addEntityList(QueuePriorityEnum::LOW, [5, 6]);41+42+$this->assertSame([1, 2], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));43+$this->assertSame([3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::NORMAL));44+$this->assertSame([5, 6], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::LOW));45+ }46+47+public function testGetEntityListItemsByGroupReturnsEmptyArrayForUnknownGroup(): void15 {48 {16-$priority = ['p1', 'p2'];49+$selectionList = new SelectionList();17-$normal = ['n1', 'n2'];50+18-$selectionList = new SelectionList($priority, $normal);51+$this->assertSame([], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));52+ }195320-$this->assertSame($priority, $selectionList->getHighPriorityEntityIds());54+public function testGetEntityListGroups(): void21-$this->assertSame($normal, $selectionList->getNormalPriorityEntityId());55+ {56+$selectionList = new SelectionList();57+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);58+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2]);225923-$this->assertSame(['p1', 'p2', 'n1', 'n2'], $selectionList->getAllIds());60+$this->assertSame(['high', 'normal'], $selectionList->getEntityListGroups());24 }61 }256226public function testCountReturnsTotalCount(): void63public function testCountReturnsTotalCount(): void27 {64 {28-$selectionList = new SelectionList(['p1'], ['n1', 'n2']);65+$selectionList = new SelectionList();66+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);67+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2, 3]);68+29$this->assertSame(3, $selectionList->count());69$this->assertSame(3, $selectionList->count());30 }70 }317132-public function testIsEmptyReturnsTrueWhenBothListsAreEmpty(): void72+public function testIsEmptyReturnsTrueWhenNoEntitiesAdded(): void33 {73 {34-$selectionList = new SelectionList([], []);74+$selectionList = new SelectionList();75+35$this->assertTrue($selectionList->isEmpty());76$this->assertTrue($selectionList->isEmpty());36 }77 }377838-public function testIsEmptyReturnsFalseWhenAnyListIsNotEmpty(): void79+public function testIsEmptyReturnsFalseWhenEntitiesAdded(): void39 {80 {40-$selectionList = new SelectionList(['p1'], []);81+$selectionList = new SelectionList();41-$this->assertFalse($selectionList->isEmpty());82+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);428343-$selectionList2 = new SelectionList([], ['n1']);84+$this->assertFalse($selectionList->isEmpty());44-$this->assertFalse($selectionList2->isEmpty());45 }85 }468647-public function testIsStaleChunkSelected(): void87+public function testMarkStaleAndIsStaleChunkSelected(): void48 {88 {49-$selectionList = new SelectionList([], [], true);89+$selectionList = new SelectionList();50-$this->assertTrue($selectionList->isStaleChunkSelected());90+91+$this->assertFalse($selectionList->isStaleChunkSelected());92+93+$selectionList->markStale();519452-$selectionList2 = new SelectionList([], [], false);95+$this->assertTrue($selectionList->isStaleChunkSelected());53-$this->assertFalse($selectionList2->isStaleChunkSelected());54 }96 }559756public function testIsFullChunk(): void98public function testIsFullChunk(): void57 {99 {58-$chunkSize = 200;100+$selectionList = new SelectionList();59-101+$selectionList->setChunkSize(self::CHUNK_SIZE);60-$fullList = range(1, $chunkSize);102+61-$selectionList = new SelectionList(103+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, self::CHUNK_SIZE));62- priorityEntityIdList: $fullList,104+63- normalEntityIdList: [],105+$this->assertTrue($selectionList->isFullChunk());64- chunkSize: $chunkSize,106+ }65- );107+108+public function testIsNotFullChunkWhenBelowChunkSize(): void109+ {110+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);111+112+$selectionList = new SelectionList();113+$selectionList->setChunkSize(self::CHUNK_SIZE);114+115+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range(1, $halfRange));116+117+$this->assertFalse($selectionList->isFullChunk());118+ }119+120+public function testIsFullChunkAcrossMultiplePriorityGroups(): void121+ {122+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);123+124+$selectionList = new SelectionList();125+$selectionList->setChunkSize(self::CHUNK_SIZE);126+127+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, $halfRange));128+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range($halfRange + 1, self::CHUNK_SIZE));129+130+$this->assertTrue($selectionList->isFullChunk());131+ }132+133+public function testSetChunkSizeAffectsIsFullChunk(): void134+ {135+$selectionList = new SelectionList();136+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [1, 2, 3]);137+138+$selectionList->setChunkSize(3);66$this->assertTrue($selectionList->isFullChunk());139$this->assertTrue($selectionList->isFullChunk());6714068-$halfRange = (int) ceil($chunkSize / 2);141+$selectionList->setChunkSize(50);69-142+$this->assertFalse($selectionList->isFullChunk());70-$notFullList = range(1, $halfRange);71-$selectionList2 = new SelectionList(72- priorityEntityIdList: $notFullList,73- normalEntityIdList: [],74- chunkSize: $chunkSize,75- );76-$this->assertFalse($selectionList2->isFullChunk());77-78-$priorityRange = range(1, $halfRange);79-$normalRange = range($halfRange + 1, $chunkSize);80-81-$selectionList3 = new SelectionList(82- priorityEntityIdList: $priorityRange,83- normalEntityIdList: $normalRange,84- chunkSize: $chunkSize,85- );86-$this->assertTrue($selectionList3->isFullChunk());87 }143 }88}144}</selection>” selected.
Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
Expand
Listen
Gemini said
Gemini said
Here is a precise and concise summary of the code selection, which refactors
SelectionListTest
to accommodate a shift from fixed high/normal priority properties to a more dynamic, enum-driven priority group architecture.
Refactored Priority Handling
Refactored Priority Handling
Dynamic Priority Groups:
Replaces fixed high/normal array parameters with the
QueuePriorityEnum
(
HIGH
,
NORMAL
,
LOW
), allowing entity lists to be managed dynamically by group types.
Merged Registrations:
Validates that multiple
addEntityList()
calls targeting the same priority level properly merge their data instead of overwriting it.
Group Querying:
Tests new methods
getEntityListItemsByGroup()
and
getEntityListGroups()
to retrieve group-specific IDs or an array of active group names (e.g.,
['high', 'normal']
).
Updated State and Count Validations
Updated State and Count Validations
Instantiation:
Tests now instantiate
SelectionList
without initial constructor arguments, using setters and action methods instead.
Empty States:
Updates assertions (
isEmpty()
) to verify state based on whether any entities have been dynamically added, rather than checking pre-defined constructor arrays.
Stale Flags:
Changes from passing a
stale
boolean via the constructor to explicitly triggering a mutable
$selectionList->markStale()
method.
Chunk Capacity Behavior
Chunk Capacity Behavior
Flexible Chunk Sizes:
Introduces a
setChunkSize()
method, replacing the constructor-configured chunk boundary.
Capacity Assertions:
Retains and updates the logic for
isFullChunk()
, ensuring it accurately evaluates capacity when elements span multiple dynamic priority groups or when the chunk limit is altered mid-lifecycle.
Good response
Bad response
Share & export
Copy
Show more options
Copy prompt
You said Are there any issues or potential bolltenecks
You said
Are there any issues or potential bolltenecks
Listen
Show thinking
Gemini said
Gemini said
Based on the test diff you provided, we can infer a few potential issues and architectural bottlenecks in the underlying
SelectionList
implementation. While the tests are well-structured, the behavior they describe hints at a few areas you might want to keep an eye on, particularly for an Elasticsearch (ES) processor queue.
Here are the potential issues and bottlenecks to consider:
1. Array Merging Overhead (Performance)
1. Array Merging Overhead (Performance)
The
testAddEntityListMergesMultipleCallsForSamePriority
test shows that calling
addEntityList()
multiple times for the same priority group merges the arrays.
The Bottleneck:
If the underlying implementation uses
array_merge()
inside a loop to append these IDs, it creates a new array in memory every time it's called. If you are processing thousands of entities and appending them in small batches, this can lead to memory bloat and CPU degradation due to constant array reallocation.
Mitigation:
Ensure the implementation handles batch appends efficiently (e.g., using the spread operator
[...$existing, ...$new]
or appending via references) or groups the arrays before doing a single merge.
2. Lack of Uniqueness/Deduplication (Logic)
2. Lack of Uniqueness/Deduplication (Logic)
None of the tests explicitly verify what happens if duplicate IDs are added. For example, if you call
addEntityList(QueuePriorityEnum::HIGH, [1, 2])
and then
addEntityList(QueuePriorityEnum::HIGH, [2, 3])
.
The Issue:
Does the getter return
[1, 2, 2, 3]
or
[1, 2, 3]
? If duplicates are not filtered out, your ES processor might end up indexing the same entity multiple times in a single chunk, which wastes I/O and processor cycles.
Mitigation:
The underlying class should ideally enforce uniqueness (e.g., using
array_unique()
before resolving the chunk, or using ID keys as associative array keys to naturally prevent duplicates).
3. Memory Consumption with Large Chunks (Scalability)
3. Memory Consumption with Large Chunks (Scalability)
The tests introduce
setChunkSize()
. If this chunk size is configured to be very large (e.g., tens of thousands of IDs to bulk-send to Elasticsearch).
The Bottleneck:
Holding massive arrays of IDs in memory across different priority groups can quickly hit PHP memory limits, especially if this
SelectionList
object is kept alive during a long-running daemon or cron job.
Mitigation:
Monitor memory usage if
CHUNK_SIZE
grows, and ensure the
SelectionList
object is properly destroyed (or garbage collected) after the chunk is processed to free up memory.
4. Type Juggling
4. Type Juggling
In the original code, string IDs were used (
['p1', 'p2']
). In the refactored tests, integer IDs are used (
[1, 2]
).
The Issue:
If your system handles UUIDs (strings) vs. relational DB auto-increments (integers), make sure the underlying implementation uses strict comparisons (
===
) where necessary, especially if deduplicating arrays, to prevent PHP from juggling
'1'
and
1
improperly.
Would you like me to draft a quick test case to check how the class currently handles duplicate IDs, or is deduplication intentionally handled further down your pipeline?
Good response
Bad response
Share & export
Copy
Show more options
Copy prompt
You said what about non test files
You said
what about non test files
Listen
Show thinking
Gemini said
Gemini said
Since we don't have the actual
SelectionList.php
file, we have to reverse-engineer its implementation based on the test behaviors. Moving from a constructor-based, fixed-property model to a dynamic, mutable model introduces several potential pitfalls in the implementation file itself.
Here are the specific bottlenecks and issues to watch out for in the
SelectionList.php
source code:
1. The count() Method Implementation (Performance Trap)
1. The
count()
Method Implementation (Performance Trap)
The Risk:
If
count()
is implemented by calling
$this->getAllIds()
and counting the resulting merged array (e.g.,
return count($this->getAllIds());
), it will be highly inefficient. It would allocate a brand-new array in memory just to determine its length.
The Fix:
count()
should mathematically sum the sizes of the underlying group arrays without merging them:
return array_sum(array_map('count', $this->entityLists));
2. Loss of Immutability (State Management)
2. Loss of Immutability (State Management)
The Risk:
The original code passed all data via the constructor, implying the DTO (Data Transfer Object) was immutable once created. The refactored version introduces mutability (
addEntityList()
,
setChunkSize()
,
markStale()
). DTOs are typically passed between architectural layers; if one layer modifies the chunk size or adds entities while another is processing it, it can cause unpredictable side effects or race conditions in your queue processor.
The Fix:
Ensure that this object is not shared across asynchronous contexts, or consider returning cloned instances when mutating state if strict immutability is required.
3. Enum Array Key Violations (PHP Quirks)
3. Enum Array Key Violations (PHP Quirks)
The Risk:
The tests show
QueuePriorityEnum::HIGH
being passed to methods. If the underlying code attempts to use this Enum directly as an array key (e.g.,
$this->lists[$priority] = $ids;
), PHP will throw an error because objects (including Enums) cannot be used as standard array keys.
The Fix:
The implementation must map the Enum to its underlying scalar value (e.g.,
$this->lists[$priority->value]
) or use PHP's
WeakMap
or
SplObjectStorage
, though standard arrays using
$priority->value
are much faster for simple lists.
4. Uninitialized State Defaults (Logic Errors)
4. Uninitialized State Defaults (Logic Errors)
The Risk:
The tests instantiate
new SelectionList()
without arguments, then later call
$selectionList->setChunkSize(100)
. If
isFullChunk()
is called
before
setChunkSize()
is invoked, what happens?
The Fix:
Ensure
SelectionList
has a sensible default for chunk size (e.g.,
private int $chunkSize = 0;
or a system default) to prevent uninitialized property errors or division-by-zero scenarios if your logic ever relies on chunk math.
5. getAllIds() Repeated Execution (CPU Overhead)
5.
getAllIds()
Repeated Execution (CPU Overhead)
The Risk:
If
getAllIds()
dynamically merges arrays (
array_merge(...$this->lists)
) every time it is invoked, and your ES processor calls this method inside a loop, it will spike CPU usage.
The Fix:
If the list is read frequently, the implementation should either cache the merged result and invalidate that cache when
addEntityList()
is called, or the caller should assign the result to a local variable before iterating.
Would you like me to draft an optimal, memory-efficient skeleton for the
SelectionList.php
implementation that avoids these specific pitfalls?
Good response
Bad response
Share & export
Copy
Show more options
Copy prompt
Edit
You said can't you the PR. How does it work when I click summarize page in gemini via firefox
You said
can't you the PR. How does it work when I click summarize page in gemini via firefox
Listen...
|
[{"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":"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 I’m on page “<tabTitle>JY-20808 low priority indexing queue by Vasil-Jimi</tabTitle>” with “<selection>@@ -5,84 +5,140 @@5namespace Tests\\Unit\\Component\\ES\\Processor\\DTOs;5namespace Tests\\Unit\\Component\\ES\\Processor\\DTOs;667use Jiminny\\Component\\ES\\Processor\\DTOs\\SelectionList;7use Jiminny\\Component\\ES\\Processor\\DTOs\\SelectionList;8+use Jiminny\\Component\\ES\\QueuePriorityEnum;8use PHPUnit\\Framework\\Attributes\\CoversClass;9use PHPUnit\\Framework\\Attributes\\CoversClass;9use PHPUnit\\Framework\\TestCase;10use PHPUnit\\Framework\\TestCase;101111#[CoversClass(SelectionList::class)]12#[CoversClass(SelectionList::class)]12final class SelectionListTest extends TestCase13final class SelectionListTest extends TestCase13{14{14-public function testGetEntityIds(): void15+private const int CHUNK_SIZE = 100;16+17+public function testAddEntityListAndGetAllIds(): void18+ {19+$selectionList = new SelectionList();20+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);21+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);22+23+$this->assertSame([1, 2, 3, 4], $selectionList->getAllIds());24+ }25+26+public function testAddEntityListMergesMultipleCallsForSamePriority(): void27+ {28+$selectionList = new SelectionList();29+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);30+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [3, 4]);31+32+$this->assertSame([1, 2, 3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));33+ }34+35+public function testGetEntityListItemsByGroup(): void36+ {37+$selectionList = new SelectionList();38+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);39+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);40+$selectionList->addEntityList(QueuePriorityEnum::LOW, [5, 6]);41+42+$this->assertSame([1, 2], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));43+$this->assertSame([3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::NORMAL));44+$this->assertSame([5, 6], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::LOW));45+ }46+47+public function testGetEntityListItemsByGroupReturnsEmptyArrayForUnknownGroup(): void15 {48 {16-$priority = ['p1', 'p2'];49+$selectionList = new SelectionList();17-$normal = ['n1', 'n2'];50+18-$selectionList = new SelectionList($priority, $normal);51+$this->assertSame([], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));52+ }195320-$this->assertSame($priority, $selectionList->getHighPriorityEntityIds());54+public function testGetEntityListGroups(): void21-$this->assertSame($normal, $selectionList->getNormalPriorityEntityId());55+ {56+$selectionList = new SelectionList();57+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);58+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2]);225923-$this->assertSame(['p1', 'p2', 'n1', 'n2'], $selectionList->getAllIds());60+$this->assertSame(['high', 'normal'], $selectionList->getEntityListGroups());24 }61 }256226public function testCountReturnsTotalCount(): void63public function testCountReturnsTotalCount(): void27 {64 {28-$selectionList = new SelectionList(['p1'], ['n1', 'n2']);65+$selectionList = new SelectionList();66+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);67+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2, 3]);68+29$this->assertSame(3, $selectionList->count());69$this->assertSame(3, $selectionList->count());30 }70 }317132-public function testIsEmptyReturnsTrueWhenBothListsAreEmpty(): void72+public function testIsEmptyReturnsTrueWhenNoEntitiesAdded(): void33 {73 {34-$selectionList = new SelectionList([], []);74+$selectionList = new SelectionList();75+35$this->assertTrue($selectionList->isEmpty());76$this->assertTrue($selectionList->isEmpty());36 }77 }377838-public function testIsEmptyReturnsFalseWhenAnyListIsNotEmpty(): void79+public function testIsEmptyReturnsFalseWhenEntitiesAdded(): void39 {80 {40-$selectionList = new SelectionList(['p1'], []);81+$selectionList = new SelectionList();41-$this->assertFalse($selectionList->isEmpty());82+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);428343-$selectionList2 = new SelectionList([], ['n1']);84+$this->assertFalse($selectionList->isEmpty());44-$this->assertFalse($selectionList2->isEmpty());45 }85 }468647-public function testIsStaleChunkSelected(): void87+public function testMarkStaleAndIsStaleChunkSelected(): void48 {88 {49-$selectionList = new SelectionList([], [], true);89+$selectionList = new SelectionList();50-$this->assertTrue($selectionList->isStaleChunkSelected());90+91+$this->assertFalse($selectionList->isStaleChunkSelected());92+93+$selectionList->markStale();519452-$selectionList2 = new SelectionList([], [], false);95+$this->assertTrue($selectionList->isStaleChunkSelected());53-$this->assertFalse($selectionList2->isStaleChunkSelected());54 }96 }559756public function testIsFullChunk(): void98public function testIsFullChunk(): void57 {99 {58-$chunkSize = 200;100+$selectionList = new SelectionList();59-101+$selectionList->setChunkSize(self::CHUNK_SIZE);60-$fullList = range(1, $chunkSize);102+61-$selectionList = new SelectionList(103+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, self::CHUNK_SIZE));62- priorityEntityIdList: $fullList,104+63- normalEntityIdList: [],105+$this->assertTrue($selectionList->isFullChunk());64- chunkSize: $chunkSize,106+ }65- );107+108+public function testIsNotFullChunkWhenBelowChunkSize(): void109+ {110+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);111+112+$selectionList = new SelectionList();113+$selectionList->setChunkSize(self::CHUNK_SIZE);114+115+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range(1, $halfRange));116+117+$this->assertFalse($selectionList->isFullChunk());118+ }119+120+public function testIsFullChunkAcrossMultiplePriorityGroups(): void121+ {122+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);123+124+$selectionList = new SelectionList();125+$selectionList->setChunkSize(self::CHUNK_SIZE);126+127+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, $halfRange));128+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range($halfRange + 1, self::CHUNK_SIZE));129+130+$this->assertTrue($selectionList->isFullChunk());131+ }132+133+public function testSetChunkSizeAffectsIsFullChunk(): void134+ {135+$selectionList = new SelectionList();136+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [1, 2, 3]);137+138+$selectionList->setChunkSize(3);66$this->assertTrue($selectionList->isFullChunk());139$this->assertTrue($selectionList->isFullChunk());6714068-$halfRange = (int) ceil($chunkSize / 2);141+$selectionList->setChunkSize(50);69-142+$this->assertFalse($selectionList->isFullChunk());70-$notFullList = range(1, $halfRange);71-$selectionList2 = new SelectionList(72- priorityEntityIdList: $notFullList,73- normalEntityIdList: [],74- chunkSize: $chunkSize,75- );76-$this->assertFalse($selectionList2->isFullChunk());77-78-$priorityRange = range(1, $halfRange);79-$normalRange = range($halfRange + 1, $chunkSize);80-81-$selectionList3 = new SelectionList(82- priorityEntityIdList: $priorityRange,83- normalEntityIdList: $normalRange,84- chunkSize: $chunkSize,85- );86-$this->assertTrue($selectionList3->isFullChunk());87 }143 }88}144}</selection>” selected. Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.","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":"I’m on page “<tabTitle>JY-20808 low priority indexing queue by Vasil-Jimi</tabTitle>” with “<selection>@@ -5,84 +5,140 @@5namespace Tests\\Unit\\Component\\ES\\Processor\\DTOs;5namespace Tests\\Unit\\Component\\ES\\Processor\\DTOs;667use Jiminny\\Component\\ES\\Processor\\DTOs\\SelectionList;7use Jiminny\\Component\\ES\\Processor\\DTOs\\SelectionList;8+use Jiminny\\Component\\ES\\QueuePriorityEnum;8use PHPUnit\\Framework\\Attributes\\CoversClass;9use PHPUnit\\Framework\\Attributes\\CoversClass;9use PHPUnit\\Framework\\TestCase;10use PHPUnit\\Framework\\TestCase;101111#[CoversClass(SelectionList::class)]12#[CoversClass(SelectionList::class)]12final class SelectionListTest extends TestCase13final class SelectionListTest extends TestCase13{14{14-public function testGetEntityIds(): void15+private const int CHUNK_SIZE = 100;16+17+public function testAddEntityListAndGetAllIds(): void18+ {19+$selectionList = new SelectionList();20+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);21+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);22+23+$this->assertSame([1, 2, 3, 4], $selectionList->getAllIds());24+ }25+26+public function testAddEntityListMergesMultipleCallsForSamePriority(): void27+ {28+$selectionList = new SelectionList();29+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);30+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [3, 4]);31+32+$this->assertSame([1, 2, 3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));33+ }34+35+public function testGetEntityListItemsByGroup(): void36+ {37+$selectionList = new SelectionList();38+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);39+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);40+$selectionList->addEntityList(QueuePriorityEnum::LOW, [5, 6]);41+42+$this->assertSame([1, 2], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));43+$this->assertSame([3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::NORMAL));44+$this->assertSame([5, 6], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::LOW));45+ }46+47+public function testGetEntityListItemsByGroupReturnsEmptyArrayForUnknownGroup(): void15 {48 {16-$priority = ['p1', 'p2'];49+$selectionList = new SelectionList();17-$normal = ['n1', 'n2'];50+18-$selectionList = new SelectionList($priority, $normal);51+$this->assertSame([], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));52+ }195320-$this->assertSame($priority, $selectionList->getHighPriorityEntityIds());54+public function testGetEntityListGroups(): void21-$this->assertSame($normal, $selectionList->getNormalPriorityEntityId());55+ {56+$selectionList = new SelectionList();57+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);58+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2]);225923-$this->assertSame(['p1', 'p2', 'n1', 'n2'], $selectionList->getAllIds());60+$this->assertSame(['high', 'normal'], $selectionList->getEntityListGroups());24 }61 }256226public function testCountReturnsTotalCount(): void63public function testCountReturnsTotalCount(): void27 {64 {28-$selectionList = new SelectionList(['p1'], ['n1', 'n2']);65+$selectionList = new SelectionList();66+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);67+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2, 3]);68+29$this->assertSame(3, $selectionList->count());69$this->assertSame(3, $selectionList->count());30 }70 }317132-public function testIsEmptyReturnsTrueWhenBothListsAreEmpty(): void72+public function testIsEmptyReturnsTrueWhenNoEntitiesAdded(): void33 {73 {34-$selectionList = new SelectionList([], []);74+$selectionList = new SelectionList();75+35$this->assertTrue($selectionList->isEmpty());76$this->assertTrue($selectionList->isEmpty());36 }77 }377838-public function testIsEmptyReturnsFalseWhenAnyListIsNotEmpty(): void79+public function testIsEmptyReturnsFalseWhenEntitiesAdded(): void39 {80 {40-$selectionList = new SelectionList(['p1'], []);81+$selectionList = new SelectionList();41-$this->assertFalse($selectionList->isEmpty());82+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);428343-$selectionList2 = new SelectionList([], ['n1']);84+$this->assertFalse($selectionList->isEmpty());44-$this->assertFalse($selectionList2->isEmpty());45 }85 }468647-public function testIsStaleChunkSelected(): void87+public function testMarkStaleAndIsStaleChunkSelected(): void48 {88 {49-$selectionList = new SelectionList([], [], true);89+$selectionList = new SelectionList();50-$this->assertTrue($selectionList->isStaleChunkSelected());90+91+$this->assertFalse($selectionList->isStaleChunkSelected());92+93+$selectionList->markStale();519452-$selectionList2 = new SelectionList([], [], false);95+$this->assertTrue($selectionList->isStaleChunkSelected());53-$this->assertFalse($selectionList2->isStaleChunkSelected());54 }96 }559756public function testIsFullChunk(): void98public function testIsFullChunk(): void57 {99 {58-$chunkSize = 200;100+$selectionList = new SelectionList();59-101+$selectionList->setChunkSize(self::CHUNK_SIZE);60-$fullList = range(1, $chunkSize);102+61-$selectionList = new SelectionList(103+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, self::CHUNK_SIZE));62- priorityEntityIdList: $fullList,104+63- normalEntityIdList: [],105+$this->assertTrue($selectionList->isFullChunk());64- chunkSize: $chunkSize,106+ }65- );107+108+public function testIsNotFullChunkWhenBelowChunkSize(): void109+ {110+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);111+112+$selectionList = new SelectionList();113+$selectionList->setChunkSize(self::CHUNK_SIZE);114+115+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range(1, $halfRange));116+117+$this->assertFalse($selectionList->isFullChunk());118+ }119+120+public function testIsFullChunkAcrossMultiplePriorityGroups(): void121+ {122+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);123+124+$selectionList = new SelectionList();125+$selectionList->setChunkSize(self::CHUNK_SIZE);126+127+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, $halfRange));128+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range($halfRange + 1, self::CHUNK_SIZE));129+130+$this->assertTrue($selectionList->isFullChunk());131+ }132+133+public function testSetChunkSizeAffectsIsFullChunk(): void134+ {135+$selectionList = new SelectionList();136+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [1, 2, 3]);137+138+$selectionList->setChunkSize(3);66$this->assertTrue($selectionList->isFullChunk());139$this->assertTrue($selectionList->isFullChunk());6714068-$halfRange = (int) ceil($chunkSize / 2);141+$selectionList->setChunkSize(50);69-142+$this->assertFalse($selectionList->isFullChunk());70-$notFullList = range(1, $halfRange);71-$selectionList2 = new SelectionList(72- priorityEntityIdList: $notFullList,73- normalEntityIdList: [],74- chunkSize: $chunkSize,75- );76-$this->assertFalse($selectionList2->isFullChunk());77-78-$priorityRange = range(1, $halfRange);79-$normalRange = range($halfRange + 1, $chunkSize);80-81-$selectionList3 = new SelectionList(82- priorityEntityIdList: $priorityRange,83- normalEntityIdList: $normalRange,84- chunkSize: $chunkSize,85- );86-$this->assertTrue($selectionList3->isFullChunk());87 }143 }88}144}</selection>” selected.","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Expand","depth":21,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"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":"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":"Here is a precise and concise summary of the code selection, which refactors","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SelectionListTest","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"to accommodate a shift from fixed high/normal priority properties to a more dynamic, enum-driven priority group architecture.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Refactored Priority Handling","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Refactored Priority Handling","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Dynamic Priority Groups:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Replaces fixed high/normal array parameters with the","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"QueuePriorityEnum","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"HIGH","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"NORMAL","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"LOW","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"), allowing entity lists to be managed dynamically by group types.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Merged Registrations:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Validates that multiple","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"addEntityList()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"calls targeting the same priority level properly merge their data instead of overwriting it.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Group Querying:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Tests new methods","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"getEntityListItemsByGroup()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"and","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"getEntityListGroups()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"to retrieve group-specific IDs or an array of active group names (e.g.,","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"['high', 'normal']","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":").","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Updated State and Count Validations","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Updated State and Count Validations","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Instantiation:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Tests now instantiate","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SelectionList","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"without initial constructor arguments, using setters and action methods instead.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Empty States:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Updates assertions (","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"isEmpty()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":") to verify state based on whether any entities have been dynamically added, rather than checking pre-defined constructor arrays.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Stale Flags:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Changes from passing a","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"stale","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"boolean via the constructor to explicitly triggering a mutable","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$selectionList->markStale()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"method.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Chunk Capacity Behavior","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Chunk Capacity Behavior","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Flexible Chunk Sizes:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Introduces a","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"setChunkSize()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"method, replacing the constructor-configured chunk boundary.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Capacity Assertions:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Retains and updates the logic for","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"isFullChunk()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":", ensuring it accurately evaluates capacity when elements span multiple dynamic priority groups or when the chunk limit is altered mid-lifecycle.","depth":26,"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":"AXHeading","text":"You said Are there any issues or potential bolltenecks","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":"Are there any issues or potential bolltenecks","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":"Based on the test diff you provided, we can infer a few potential issues and architectural bottlenecks in the underlying","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SelectionList","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"implementation. While the tests are well-structured, the behavior they describe hints at a few areas you might want to keep an eye on, particularly for an Elasticsearch (ES) processor queue.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Here are the potential issues and bottlenecks to consider:","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"1. Array Merging Overhead (Performance)","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1. Array Merging Overhead (Performance)","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"testAddEntityListMergesMultipleCallsForSamePriority","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"test shows that calling","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"addEntityList()","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"multiple times for the same priority group merges the arrays.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The Bottleneck:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"If the underlying implementation uses","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"array_merge()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"inside a loop to append these IDs, it creates a new array in memory every time it's called. If you are processing thousands of entities and appending them in small batches, this can lead to memory bloat and CPU degradation due to constant array reallocation.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Mitigation:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Ensure the implementation handles batch appends efficiently (e.g., using the spread operator","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"[...$existing, ...$new]","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"or appending via references) or groups the arrays before doing a single merge.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"2. Lack of Uniqueness/Deduplication (Logic)","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2. Lack of Uniqueness/Deduplication (Logic)","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"None of the tests explicitly verify what happens if duplicate IDs are added. For example, if you call","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"addEntityList(QueuePriorityEnum::HIGH, [1, 2])","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"and then","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"addEntityList(QueuePriorityEnum::HIGH, [2, 3])","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":".","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The Issue:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Does the getter return","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"[1, 2, 2, 3]","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"or","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"[1, 2, 3]","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"? If duplicates are not filtered out, your ES processor might end up indexing the same entity multiple times in a single chunk, which wastes I/O and processor cycles.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Mitigation:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The underlying class should ideally enforce uniqueness (e.g., using","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"array_unique()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"before resolving the chunk, or using ID keys as associative array keys to naturally prevent duplicates).","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"3. Memory Consumption with Large Chunks (Scalability)","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3. Memory Consumption with Large Chunks (Scalability)","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The tests introduce","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"setChunkSize()","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":". If this chunk size is configured to be very large (e.g., tens of thousands of IDs to bulk-send to Elasticsearch).","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The Bottleneck:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Holding massive arrays of IDs in memory across different priority groups can quickly hit PHP memory limits, especially if this","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SelectionList","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"object is kept alive during a long-running daemon or cron job.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Mitigation:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Monitor memory usage if","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"CHUNK_SIZE","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"grows, and ensure the","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SelectionList","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"object is properly destroyed (or garbage collected) after the chunk is processed to free up memory.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"4. Type Juggling","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"4. Type Juggling","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"In the original code, string IDs were used (","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"['p1', 'p2']","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"). In the refactored tests, integer IDs are used (","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"[1, 2]","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":").","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The Issue:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"If your system handles UUIDs (strings) vs. relational DB auto-increments (integers), make sure the underlying implementation uses strict comparisons (","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"===","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":") where necessary, especially if deduplicating arrays, to prevent PHP from juggling","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"'1'","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"and","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"improperly.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Would you like me to draft a quick test case to check how the class currently handles duplicate IDs, or is deduplication intentionally handled further down your pipeline?","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":"AXHeading","text":"You said what about non test files","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":"what about non test files","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":"Since we don't have the actual","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SelectionList.php","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"file, we have to reverse-engineer its implementation based on the test behaviors. Moving from a constructor-based, fixed-property model to a dynamic, mutable model introduces several potential pitfalls in the implementation file itself.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Here are the specific bottlenecks and issues to watch out for in the","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SelectionList.php","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"source code:","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"1. The count() Method Implementation (Performance Trap)","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1. The","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"count()","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Method Implementation (Performance Trap)","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The Risk:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"If","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"count()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"is implemented by calling","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$this->getAllIds()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"and counting the resulting merged array (e.g.,","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"return count($this->getAllIds());","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"), it will be highly inefficient. It would allocate a brand-new array in memory just to determine its length.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The Fix:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"count()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"should mathematically sum the sizes of the underlying group arrays without merging them:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"return array_sum(array_map('count', $this->entityLists));","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"2. Loss of Immutability (State Management)","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2. Loss of Immutability (State Management)","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The Risk:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The original code passed all data via the constructor, implying the DTO (Data Transfer Object) was immutable once created. The refactored version introduces mutability (","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"addEntityList()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"setChunkSize()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"markStale()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"). DTOs are typically passed between architectural layers; if one layer modifies the chunk size or adds entities while another is processing it, it can cause unpredictable side effects or race conditions in your queue processor.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The Fix:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Ensure that this object is not shared across asynchronous contexts, or consider returning cloned instances when mutating state if strict immutability is required.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"3. Enum Array Key Violations (PHP Quirks)","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3. Enum Array Key Violations (PHP Quirks)","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The Risk:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The tests show","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"QueuePriorityEnum::HIGH","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"being passed to methods. If the underlying code attempts to use this Enum directly as an array key (e.g.,","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$this->lists[$priority] = $ids;","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"), PHP will throw an error because objects (including Enums) cannot be used as standard array keys.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The Fix:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The implementation must map the Enum to its underlying scalar value (e.g.,","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$this->lists[$priority->value]","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":") or use PHP's","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"WeakMap","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"or","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SplObjectStorage","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":", though standard arrays using","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$priority->value","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"are much faster for simple lists.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"4. Uninitialized State Defaults (Logic Errors)","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"4. Uninitialized State Defaults (Logic Errors)","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The Risk:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The tests instantiate","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"new SelectionList()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"without arguments, then later call","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$selectionList->setChunkSize(100)","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":". If","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"isFullChunk()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"is called","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"before","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"setChunkSize()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"is invoked, what happens?","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The Fix:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Ensure","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SelectionList","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"has a sensible default for chunk size (e.g.,","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private int $chunkSize = 0;","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"or a system default) to prevent uninitialized property errors or division-by-zero scenarios if your logic ever relies on chunk math.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"5. getAllIds() Repeated Execution (CPU Overhead)","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"5.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"getAllIds()","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Repeated Execution (CPU Overhead)","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The Risk:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"If","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"getAllIds()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"dynamically merges arrays (","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"array_merge(...$this->lists)","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":") every time it is invoked, and your ES processor calls this method inside a loop, it will spike CPU usage.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The Fix:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"If the list is read frequently, the implementation should either cache the merged result and invalidate that cache when","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"addEntityList()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"is called, or the caller should assign the result to a local variable before iterating.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Would you like me to draft an optimal, memory-efficient skeleton for the","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SelectionList.php","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"implementation that avoids these specific pitfalls?","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Good response","depth":22,"bounds":{"left":0.1100399,"top":0.0,"width":0.010638298,"height":0.025538707},"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,"bounds":{"left":0.120678194,"top":0.0,"width":0.010638298,"height":0.025538707},"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,"bounds":{"left":0.13131648,"top":0.0,"width":0.010638298,"height":0.025538707},"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,"bounds":{"left":0.1419548,"top":0.0,"width":0.010638298,"height":0.025538707},"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,"bounds":{"left":0.15259309,"top":0.0,"width":0.010638298,"height":0.025538707},"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.0015961692,"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.0015961692,"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 can't you the PR. How does it work when I click summarize page in gemini via firefox","depth":21,"bounds":{"left":0.20578457,"top":0.011173184,"width":0.15026596,"height":0.03830806},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"You said","depth":23,"bounds":{"left":0.079288565,"top":0.011971269,"width":0.019946808,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"can't you the PR. How does it work when I click summarize page in gemini via firefox","depth":23,"bounds":{"left":0.20578457,"top":0.012769354,"width":0.14029256,"height":0.035514764},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Listen","depth":22,"bounds":{"left":0.3480718,"top":0.08140463,"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}]...
|
-640786289591033679
|
5896451135540654101
|
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
Copy prompt
You said I’m on page “<tabTitle>JY-20808 low priority indexing queue by Vasil-Jimi</tabTitle>” with “<selection>@@ -5,84 +5,140 @@5namespace Tests\Unit\Component\ES\Processor\DTOs;5namespace Tests\Unit\Component\ES\Processor\DTOs;667use Jiminny\Component\ES\Processor\DTOs\SelectionList;7use Jiminny\Component\ES\Processor\DTOs\SelectionList;8+use Jiminny\Component\ES\QueuePriorityEnum;8use PHPUnit\Framework\Attributes\CoversClass;9use PHPUnit\Framework\Attributes\CoversClass;9use PHPUnit\Framework\TestCase;10use PHPUnit\Framework\TestCase;101111#[CoversClass(SelectionList::class)]12#[CoversClass(SelectionList::class)]12final class SelectionListTest extends TestCase13final class SelectionListTest extends TestCase13{14{14-public function testGetEntityIds(): void15+private const int CHUNK_SIZE = 100;16+17+public function testAddEntityListAndGetAllIds(): void18+ {19+$selectionList = new SelectionList();20+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);21+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);22+23+$this->assertSame([1, 2, 3, 4], $selectionList->getAllIds());24+ }25+26+public function testAddEntityListMergesMultipleCallsForSamePriority(): void27+ {28+$selectionList = new SelectionList();29+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);30+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [3, 4]);31+32+$this->assertSame([1, 2, 3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));33+ }34+35+public function testGetEntityListItemsByGroup(): void36+ {37+$selectionList = new SelectionList();38+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);39+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);40+$selectionList->addEntityList(QueuePriorityEnum::LOW, [5, 6]);41+42+$this->assertSame([1, 2], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));43+$this->assertSame([3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::NORMAL));44+$this->assertSame([5, 6], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::LOW));45+ }46+47+public function testGetEntityListItemsByGroupReturnsEmptyArrayForUnknownGroup(): void15 {48 {16-$priority = ['p1', 'p2'];49+$selectionList = new SelectionList();17-$normal = ['n1', 'n2'];50+18-$selectionList = new SelectionList($priority, $normal);51+$this->assertSame([], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));52+ }195320-$this->assertSame($priority, $selectionList->getHighPriorityEntityIds());54+public function testGetEntityListGroups(): void21-$this->assertSame($normal, $selectionList->getNormalPriorityEntityId());55+ {56+$selectionList = new SelectionList();57+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);58+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2]);225923-$this->assertSame(['p1', 'p2', 'n1', 'n2'], $selectionList->getAllIds());60+$this->assertSame(['high', 'normal'], $selectionList->getEntityListGroups());24 }61 }256226public function testCountReturnsTotalCount(): void63public function testCountReturnsTotalCount(): void27 {64 {28-$selectionList = new SelectionList(['p1'], ['n1', 'n2']);65+$selectionList = new SelectionList();66+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);67+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2, 3]);68+29$this->assertSame(3, $selectionList->count());69$this->assertSame(3, $selectionList->count());30 }70 }317132-public function testIsEmptyReturnsTrueWhenBothListsAreEmpty(): void72+public function testIsEmptyReturnsTrueWhenNoEntitiesAdded(): void33 {73 {34-$selectionList = new SelectionList([], []);74+$selectionList = new SelectionList();75+35$this->assertTrue($selectionList->isEmpty());76$this->assertTrue($selectionList->isEmpty());36 }77 }377838-public function testIsEmptyReturnsFalseWhenAnyListIsNotEmpty(): void79+public function testIsEmptyReturnsFalseWhenEntitiesAdded(): void39 {80 {40-$selectionList = new SelectionList(['p1'], []);81+$selectionList = new SelectionList();41-$this->assertFalse($selectionList->isEmpty());82+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);428343-$selectionList2 = new SelectionList([], ['n1']);84+$this->assertFalse($selectionList->isEmpty());44-$this->assertFalse($selectionList2->isEmpty());45 }85 }468647-public function testIsStaleChunkSelected(): void87+public function testMarkStaleAndIsStaleChunkSelected(): void48 {88 {49-$selectionList = new SelectionList([], [], true);89+$selectionList = new SelectionList();50-$this->assertTrue($selectionList->isStaleChunkSelected());90+91+$this->assertFalse($selectionList->isStaleChunkSelected());92+93+$selectionList->markStale();519452-$selectionList2 = new SelectionList([], [], false);95+$this->assertTrue($selectionList->isStaleChunkSelected());53-$this->assertFalse($selectionList2->isStaleChunkSelected());54 }96 }559756public function testIsFullChunk(): void98public function testIsFullChunk(): void57 {99 {58-$chunkSize = 200;100+$selectionList = new SelectionList();59-101+$selectionList->setChunkSize(self::CHUNK_SIZE);60-$fullList = range(1, $chunkSize);102+61-$selectionList = new SelectionList(103+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, self::CHUNK_SIZE));62- priorityEntityIdList: $fullList,104+63- normalEntityIdList: [],105+$this->assertTrue($selectionList->isFullChunk());64- chunkSize: $chunkSize,106+ }65- );107+108+public function testIsNotFullChunkWhenBelowChunkSize(): void109+ {110+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);111+112+$selectionList = new SelectionList();113+$selectionList->setChunkSize(self::CHUNK_SIZE);114+115+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range(1, $halfRange));116+117+$this->assertFalse($selectionList->isFullChunk());118+ }119+120+public function testIsFullChunkAcrossMultiplePriorityGroups(): void121+ {122+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);123+124+$selectionList = new SelectionList();125+$selectionList->setChunkSize(self::CHUNK_SIZE);126+127+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, $halfRange));128+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range($halfRange + 1, self::CHUNK_SIZE));129+130+$this->assertTrue($selectionList->isFullChunk());131+ }132+133+public function testSetChunkSizeAffectsIsFullChunk(): void134+ {135+$selectionList = new SelectionList();136+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [1, 2, 3]);137+138+$selectionList->setChunkSize(3);66$this->assertTrue($selectionList->isFullChunk());139$this->assertTrue($selectionList->isFullChunk());6714068-$halfRange = (int) ceil($chunkSize / 2);141+$selectionList->setChunkSize(50);69-142+$this->assertFalse($selectionList->isFullChunk());70-$notFullList = range(1, $halfRange);71-$selectionList2 = new SelectionList(72- priorityEntityIdList: $notFullList,73- normalEntityIdList: [],74- chunkSize: $chunkSize,75- );76-$this->assertFalse($selectionList2->isFullChunk());77-78-$priorityRange = range(1, $halfRange);79-$normalRange = range($halfRange + 1, $chunkSize);80-81-$selectionList3 = new SelectionList(82- priorityEntityIdList: $priorityRange,83- normalEntityIdList: $normalRange,84- chunkSize: $chunkSize,85- );86-$this->assertTrue($selectionList3->isFullChunk());87 }143 }88}144}</selection>” selected. Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
You said
I’m on page “<tabTitle>JY-20808 low priority indexing queue by Vasil-Jimi</tabTitle>” with “<selection>@@ -5,84 +5,140 @@5namespace Tests\Unit\Component\ES\Processor\DTOs;5namespace Tests\Unit\Component\ES\Processor\DTOs;667use Jiminny\Component\ES\Processor\DTOs\SelectionList;7use Jiminny\Component\ES\Processor\DTOs\SelectionList;8+use Jiminny\Component\ES\QueuePriorityEnum;8use PHPUnit\Framework\Attributes\CoversClass;9use PHPUnit\Framework\Attributes\CoversClass;9use PHPUnit\Framework\TestCase;10use PHPUnit\Framework\TestCase;101111#[CoversClass(SelectionList::class)]12#[CoversClass(SelectionList::class)]12final class SelectionListTest extends TestCase13final class SelectionListTest extends TestCase13{14{14-public function testGetEntityIds(): void15+private const int CHUNK_SIZE = 100;16+17+public function testAddEntityListAndGetAllIds(): void18+ {19+$selectionList = new SelectionList();20+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);21+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);22+23+$this->assertSame([1, 2, 3, 4], $selectionList->getAllIds());24+ }25+26+public function testAddEntityListMergesMultipleCallsForSamePriority(): void27+ {28+$selectionList = new SelectionList();29+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);30+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [3, 4]);31+32+$this->assertSame([1, 2, 3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));33+ }34+35+public function testGetEntityListItemsByGroup(): void36+ {37+$selectionList = new SelectionList();38+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);39+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);40+$selectionList->addEntityList(QueuePriorityEnum::LOW, [5, 6]);41+42+$this->assertSame([1, 2], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));43+$this->assertSame([3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::NORMAL));44+$this->assertSame([5, 6], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::LOW));45+ }46+47+public function testGetEntityListItemsByGroupReturnsEmptyArrayForUnknownGroup(): void15 {48 {16-$priority = ['p1', 'p2'];49+$selectionList = new SelectionList();17-$normal = ['n1', 'n2'];50+18-$selectionList = new SelectionList($priority, $normal);51+$this->assertSame([], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));52+ }195320-$this->assertSame($priority, $selectionList->getHighPriorityEntityIds());54+public function testGetEntityListGroups(): void21-$this->assertSame($normal, $selectionList->getNormalPriorityEntityId());55+ {56+$selectionList = new SelectionList();57+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);58+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2]);225923-$this->assertSame(['p1', 'p2', 'n1', 'n2'], $selectionList->getAllIds());60+$this->assertSame(['high', 'normal'], $selectionList->getEntityListGroups());24 }61 }256226public function testCountReturnsTotalCount(): void63public function testCountReturnsTotalCount(): void27 {64 {28-$selectionList = new SelectionList(['p1'], ['n1', 'n2']);65+$selectionList = new SelectionList();66+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);67+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2, 3]);68+29$this->assertSame(3, $selectionList->count());69$this->assertSame(3, $selectionList->count());30 }70 }317132-public function testIsEmptyReturnsTrueWhenBothListsAreEmpty(): void72+public function testIsEmptyReturnsTrueWhenNoEntitiesAdded(): void33 {73 {34-$selectionList = new SelectionList([], []);74+$selectionList = new SelectionList();75+35$this->assertTrue($selectionList->isEmpty());76$this->assertTrue($selectionList->isEmpty());36 }77 }377838-public function testIsEmptyReturnsFalseWhenAnyListIsNotEmpty(): void79+public function testIsEmptyReturnsFalseWhenEntitiesAdded(): void39 {80 {40-$selectionList = new SelectionList(['p1'], []);81+$selectionList = new SelectionList();41-$this->assertFalse($selectionList->isEmpty());82+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);428343-$selectionList2 = new SelectionList([], ['n1']);84+$this->assertFalse($selectionList->isEmpty());44-$this->assertFalse($selectionList2->isEmpty());45 }85 }468647-public function testIsStaleChunkSelected(): void87+public function testMarkStaleAndIsStaleChunkSelected(): void48 {88 {49-$selectionList = new SelectionList([], [], true);89+$selectionList = new SelectionList();50-$this->assertTrue($selectionList->isStaleChunkSelected());90+91+$this->assertFalse($selectionList->isStaleChunkSelected());92+93+$selectionList->markStale();519452-$selectionList2 = new SelectionList([], [], false);95+$this->assertTrue($selectionList->isStaleChunkSelected());53-$this->assertFalse($selectionList2->isStaleChunkSelected());54 }96 }559756public function testIsFullChunk(): void98public function testIsFullChunk(): void57 {99 {58-$chunkSize = 200;100+$selectionList = new SelectionList();59-101+$selectionList->setChunkSize(self::CHUNK_SIZE);60-$fullList = range(1, $chunkSize);102+61-$selectionList = new SelectionList(103+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, self::CHUNK_SIZE));62- priorityEntityIdList: $fullList,104+63- normalEntityIdList: [],105+$this->assertTrue($selectionList->isFullChunk());64- chunkSize: $chunkSize,106+ }65- );107+108+public function testIsNotFullChunkWhenBelowChunkSize(): void109+ {110+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);111+112+$selectionList = new SelectionList();113+$selectionList->setChunkSize(self::CHUNK_SIZE);114+115+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range(1, $halfRange));116+117+$this->assertFalse($selectionList->isFullChunk());118+ }119+120+public function testIsFullChunkAcrossMultiplePriorityGroups(): void121+ {122+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);123+124+$selectionList = new SelectionList();125+$selectionList->setChunkSize(self::CHUNK_SIZE);126+127+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, $halfRange));128+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range($halfRange + 1, self::CHUNK_SIZE));129+130+$this->assertTrue($selectionList->isFullChunk());131+ }132+133+public function testSetChunkSizeAffectsIsFullChunk(): void134+ {135+$selectionList = new SelectionList();136+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [1, 2, 3]);137+138+$selectionList->setChunkSize(3);66$this->assertTrue($selectionList->isFullChunk());139$this->assertTrue($selectionList->isFullChunk());6714068-$halfRange = (int) ceil($chunkSize / 2);141+$selectionList->setChunkSize(50);69-142+$this->assertFalse($selectionList->isFullChunk());70-$notFullList = range(1, $halfRange);71-$selectionList2 = new SelectionList(72- priorityEntityIdList: $notFullList,73- normalEntityIdList: [],74- chunkSize: $chunkSize,75- );76-$this->assertFalse($selectionList2->isFullChunk());77-78-$priorityRange = range(1, $halfRange);79-$normalRange = range($halfRange + 1, $chunkSize);80-81-$selectionList3 = new SelectionList(82- priorityEntityIdList: $priorityRange,83- normalEntityIdList: $normalRange,84- chunkSize: $chunkSize,85- );86-$this->assertTrue($selectionList3->isFullChunk());87 }143 }88}144}</selection>” selected.
Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
Expand
Listen
Gemini said
Gemini said
Here is a precise and concise summary of the code selection, which refactors
SelectionListTest
to accommodate a shift from fixed high/normal priority properties to a more dynamic, enum-driven priority group architecture.
Refactored Priority Handling
Refactored Priority Handling
Dynamic Priority Groups:
Replaces fixed high/normal array parameters with the
QueuePriorityEnum
(
HIGH
,
NORMAL
,
LOW
), allowing entity lists to be managed dynamically by group types.
Merged Registrations:
Validates that multiple
addEntityList()
calls targeting the same priority level properly merge their data instead of overwriting it.
Group Querying:
Tests new methods
getEntityListItemsByGroup()
and
getEntityListGroups()
to retrieve group-specific IDs or an array of active group names (e.g.,
['high', 'normal']
).
Updated State and Count Validations
Updated State and Count Validations
Instantiation:
Tests now instantiate
SelectionList
without initial constructor arguments, using setters and action methods instead.
Empty States:
Updates assertions (
isEmpty()
) to verify state based on whether any entities have been dynamically added, rather than checking pre-defined constructor arrays.
Stale Flags:
Changes from passing a
stale
boolean via the constructor to explicitly triggering a mutable
$selectionList->markStale()
method.
Chunk Capacity Behavior
Chunk Capacity Behavior
Flexible Chunk Sizes:
Introduces a
setChunkSize()
method, replacing the constructor-configured chunk boundary.
Capacity Assertions:
Retains and updates the logic for
isFullChunk()
, ensuring it accurately evaluates capacity when elements span multiple dynamic priority groups or when the chunk limit is altered mid-lifecycle.
Good response
Bad response
Share & export
Copy
Show more options
Copy prompt
You said Are there any issues or potential bolltenecks
You said
Are there any issues or potential bolltenecks
Listen
Show thinking
Gemini said
Gemini said
Based on the test diff you provided, we can infer a few potential issues and architectural bottlenecks in the underlying
SelectionList
implementation. While the tests are well-structured, the behavior they describe hints at a few areas you might want to keep an eye on, particularly for an Elasticsearch (ES) processor queue.
Here are the potential issues and bottlenecks to consider:
1. Array Merging Overhead (Performance)
1. Array Merging Overhead (Performance)
The
testAddEntityListMergesMultipleCallsForSamePriority
test shows that calling
addEntityList()
multiple times for the same priority group merges the arrays.
The Bottleneck:
If the underlying implementation uses
array_merge()
inside a loop to append these IDs, it creates a new array in memory every time it's called. If you are processing thousands of entities and appending them in small batches, this can lead to memory bloat and CPU degradation due to constant array reallocation.
Mitigation:
Ensure the implementation handles batch appends efficiently (e.g., using the spread operator
[...$existing, ...$new]
or appending via references) or groups the arrays before doing a single merge.
2. Lack of Uniqueness/Deduplication (Logic)
2. Lack of Uniqueness/Deduplication (Logic)
None of the tests explicitly verify what happens if duplicate IDs are added. For example, if you call
addEntityList(QueuePriorityEnum::HIGH, [1, 2])
and then
addEntityList(QueuePriorityEnum::HIGH, [2, 3])
.
The Issue:
Does the getter return
[1, 2, 2, 3]
or
[1, 2, 3]
? If duplicates are not filtered out, your ES processor might end up indexing the same entity multiple times in a single chunk, which wastes I/O and processor cycles.
Mitigation:
The underlying class should ideally enforce uniqueness (e.g., using
array_unique()
before resolving the chunk, or using ID keys as associative array keys to naturally prevent duplicates).
3. Memory Consumption with Large Chunks (Scalability)
3. Memory Consumption with Large Chunks (Scalability)
The tests introduce
setChunkSize()
. If this chunk size is configured to be very large (e.g., tens of thousands of IDs to bulk-send to Elasticsearch).
The Bottleneck:
Holding massive arrays of IDs in memory across different priority groups can quickly hit PHP memory limits, especially if this
SelectionList
object is kept alive during a long-running daemon or cron job.
Mitigation:
Monitor memory usage if
CHUNK_SIZE
grows, and ensure the
SelectionList
object is properly destroyed (or garbage collected) after the chunk is processed to free up memory.
4. Type Juggling
4. Type Juggling
In the original code, string IDs were used (
['p1', 'p2']
). In the refactored tests, integer IDs are used (
[1, 2]
).
The Issue:
If your system handles UUIDs (strings) vs. relational DB auto-increments (integers), make sure the underlying implementation uses strict comparisons (
===
) where necessary, especially if deduplicating arrays, to prevent PHP from juggling
'1'
and
1
improperly.
Would you like me to draft a quick test case to check how the class currently handles duplicate IDs, or is deduplication intentionally handled further down your pipeline?
Good response
Bad response
Share & export
Copy
Show more options
Copy prompt
You said what about non test files
You said
what about non test files
Listen
Show thinking
Gemini said
Gemini said
Since we don't have the actual
SelectionList.php
file, we have to reverse-engineer its implementation based on the test behaviors. Moving from a constructor-based, fixed-property model to a dynamic, mutable model introduces several potential pitfalls in the implementation file itself.
Here are the specific bottlenecks and issues to watch out for in the
SelectionList.php
source code:
1. The count() Method Implementation (Performance Trap)
1. The
count()
Method Implementation (Performance Trap)
The Risk:
If
count()
is implemented by calling
$this->getAllIds()
and counting the resulting merged array (e.g.,
return count($this->getAllIds());
), it will be highly inefficient. It would allocate a brand-new array in memory just to determine its length.
The Fix:
count()
should mathematically sum the sizes of the underlying group arrays without merging them:
return array_sum(array_map('count', $this->entityLists));
2. Loss of Immutability (State Management)
2. Loss of Immutability (State Management)
The Risk:
The original code passed all data via the constructor, implying the DTO (Data Transfer Object) was immutable once created. The refactored version introduces mutability (
addEntityList()
,
setChunkSize()
,
markStale()
). DTOs are typically passed between architectural layers; if one layer modifies the chunk size or adds entities while another is processing it, it can cause unpredictable side effects or race conditions in your queue processor.
The Fix:
Ensure that this object is not shared across asynchronous contexts, or consider returning cloned instances when mutating state if strict immutability is required.
3. Enum Array Key Violations (PHP Quirks)
3. Enum Array Key Violations (PHP Quirks)
The Risk:
The tests show
QueuePriorityEnum::HIGH
being passed to methods. If the underlying code attempts to use this Enum directly as an array key (e.g.,
$this->lists[$priority] = $ids;
), PHP will throw an error because objects (including Enums) cannot be used as standard array keys.
The Fix:
The implementation must map the Enum to its underlying scalar value (e.g.,
$this->lists[$priority->value]
) or use PHP's
WeakMap
or
SplObjectStorage
, though standard arrays using
$priority->value
are much faster for simple lists.
4. Uninitialized State Defaults (Logic Errors)
4. Uninitialized State Defaults (Logic Errors)
The Risk:
The tests instantiate
new SelectionList()
without arguments, then later call
$selectionList->setChunkSize(100)
. If
isFullChunk()
is called
before
setChunkSize()
is invoked, what happens?
The Fix:
Ensure
SelectionList
has a sensible default for chunk size (e.g.,
private int $chunkSize = 0;
or a system default) to prevent uninitialized property errors or division-by-zero scenarios if your logic ever relies on chunk math.
5. getAllIds() Repeated Execution (CPU Overhead)
5.
getAllIds()
Repeated Execution (CPU Overhead)
The Risk:
If
getAllIds()
dynamically merges arrays (
array_merge(...$this->lists)
) every time it is invoked, and your ES processor calls this method inside a loop, it will spike CPU usage.
The Fix:
If the list is read frequently, the implementation should either cache the merged result and invalidate that cache when
addEntityList()
is called, or the caller should assign the result to a local variable before iterating.
Would you like me to draft an optimal, memory-efficient skeleton for the
SelectionList.php
implementation that avoids these specific pitfalls?
Good response
Bad response
Share & export
Copy
Show more options
Copy prompt
Edit
You said can't you the PR. How does it work when I click summarize page in gemini via firefox
You said
can't you the PR. How does it work when I click summarize page in gemini via firefox
Listen...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
55659
|
NULL
|
0
|
2026-05-19T06:36:33.989578+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779172593989_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-4bd github.com/jiminny/app/pull/12082/changes#diff-4bdd02759b5e0d060dcbc8c2dcb9bdbc3d0266d9c2e29956b9d63916dae1fdd7...
|
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
Copy prompt
You said I’m on page “<tabTitle>JY-20808 low priority indexing queue by Vasil-Jimi</tabTitle>” with “<selection>@@ -5,84 +5,140 @@5namespace Tests\Unit\Component\ES\Processor\DTOs;5namespace Tests\Unit\Component\ES\Processor\DTOs;667use Jiminny\Component\ES\Processor\DTOs\SelectionList;7use Jiminny\Component\ES\Processor\DTOs\SelectionList;8+use Jiminny\Component\ES\QueuePriorityEnum;8use PHPUnit\Framework\Attributes\CoversClass;9use PHPUnit\Framework\Attributes\CoversClass;9use PHPUnit\Framework\TestCase;10use PHPUnit\Framework\TestCase;101111#[CoversClass(SelectionList::class)]12#[CoversClass(SelectionList::class)]12final class SelectionListTest extends TestCase13final class SelectionListTest extends TestCase13{14{14-public function testGetEntityIds(): void15+private const int CHUNK_SIZE = 100;16+17+public function testAddEntityListAndGetAllIds(): void18+ {19+$selectionList = new SelectionList();20+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);21+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);22+23+$this->assertSame([1, 2, 3, 4], $selectionList->getAllIds());24+ }25+26+public function testAddEntityListMergesMultipleCallsForSamePriority(): void27+ {28+$selectionList = new SelectionList();29+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);30+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [3, 4]);31+32+$this->assertSame([1, 2, 3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));33+ }34+35+public function testGetEntityListItemsByGroup(): void36+ {37+$selectionList = new SelectionList();38+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);39+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);40+$selectionList->addEntityList(QueuePriorityEnum::LOW, [5, 6]);41+42+$this->assertSame([1, 2], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));43+$this->assertSame([3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::NORMAL));44+$this->assertSame([5, 6], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::LOW));45+ }46+47+public function testGetEntityListItemsByGroupReturnsEmptyArrayForUnknownGroup(): void15 {48 {16-$priority = ['p1', 'p2'];49+$selectionList = new SelectionList();17-$normal = ['n1', 'n2'];50+18-$selectionList = new SelectionList($priority, $normal);51+$this->assertSame([], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));52+ }195320-$this->assertSame($priority, $selectionList->getHighPriorityEntityIds());54+public function testGetEntityListGroups(): void21-$this->assertSame($normal, $selectionList->getNormalPriorityEntityId());55+ {56+$selectionList = new SelectionList();57+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);58+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2]);225923-$this->assertSame(['p1', 'p2', 'n1', 'n2'], $selectionList->getAllIds());60+$this->assertSame(['high', 'normal'], $selectionList->getEntityListGroups());24 }61 }256226public function testCountReturnsTotalCount(): void63public function testCountReturnsTotalCount(): void27 {64 {28-$selectionList = new SelectionList(['p1'], ['n1', 'n2']);65+$selectionList = new SelectionList();66+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);67+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2, 3]);68+29$this->assertSame(3, $selectionList->count());69$this->assertSame(3, $selectionList->count());30 }70 }317132-public function testIsEmptyReturnsTrueWhenBothListsAreEmpty(): void72+public function testIsEmptyReturnsTrueWhenNoEntitiesAdded(): void33 {73 {34-$selectionList = new SelectionList([], []);74+$selectionList = new SelectionList();75+35$this->assertTrue($selectionList->isEmpty());76$this->assertTrue($selectionList->isEmpty());36 }77 }377838-public function testIsEmptyReturnsFalseWhenAnyListIsNotEmpty(): void79+public function testIsEmptyReturnsFalseWhenEntitiesAdded(): void39 {80 {40-$selectionList = new SelectionList(['p1'], []);81+$selectionList = new SelectionList();41-$this->assertFalse($selectionList->isEmpty());82+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);428343-$selectionList2 = new SelectionList([], ['n1']);84+$this->assertFalse($selectionList->isEmpty());44-$this->assertFalse($selectionList2->isEmpty());45 }85 }468647-public function testIsStaleChunkSelected(): void87+public function testMarkStaleAndIsStaleChunkSelected(): void48 {88 {49-$selectionList = new SelectionList([], [], true);89+$selectionList = new SelectionList();50-$this->assertTrue($selectionList->isStaleChunkSelected());90+91+$this->assertFalse($selectionList->isStaleChunkSelected());92+93+$selectionList->markStale();519452-$selectionList2 = new SelectionList([], [], false);95+$this->assertTrue($selectionList->isStaleChunkSelected());53-$this->assertFalse($selectionList2->isStaleChunkSelected());54 }96 }559756public function testIsFullChunk(): void98public function testIsFullChunk(): void57 {99 {58-$chunkSize = 200;100+$selectionList = new SelectionList();59-101+$selectionList->setChunkSize(self::CHUNK_SIZE);60-$fullList = range(1, $chunkSize);102+61-$selectionList = new SelectionList(103+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, self::CHUNK_SIZE));62- priorityEntityIdList: $fullList,104+63- normalEntityIdList: [],105+$this->assertTrue($selectionList->isFullChunk());64- chunkSize: $chunkSize,106+ }65- );107+108+public function testIsNotFullChunkWhenBelowChunkSize(): void109+ {110+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);111+112+$selectionList = new SelectionList();113+$selectionList->setChunkSize(self::CHUNK_SIZE);114+115+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range(1, $halfRange));116+117+$this->assertFalse($selectionList->isFullChunk());118+ }119+120+public function testIsFullChunkAcrossMultiplePriorityGroups(): void121+ {122+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);123+124+$selectionList = new SelectionList();125+$selectionList->setChunkSize(self::CHUNK_SIZE);126+127+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, $halfRange));128+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range($halfRange + 1, self::CHUNK_SIZE));129+130+$this->assertTrue($selectionList->isFullChunk());131+ }132+133+public function testSetChunkSizeAffectsIsFullChunk(): void134+ {135+$selectionList = new SelectionList();136+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [1, 2, 3]);137+138+$selectionList->setChunkSize(3);66$this->assertTrue($selectionList->isFullChunk());139$this->assertTrue($selectionList->isFullChunk());6714068-$halfRange = (int) ceil($chunkSize / 2);141+$selectionList->setChunkSize(50);69-142+$this->assertFalse($selectionList->isFullChunk());70-$notFullList = range(1, $halfRange);71-$selectionList2 = new SelectionList(72- priorityEntityIdList: $notFullList,73- normalEntityIdList: [],74- chunkSize: $chunkSize,75- );76-$this->assertFalse($selectionList2->isFullChunk());77-78-$priorityRange = range(1, $halfRange);79-$normalRange = range($halfRange + 1, $chunkSize);80-81-$selectionList3 = new SelectionList(82- priorityEntityIdList: $priorityRange,83- normalEntityIdList: $normalRange,84- chunkSize: $chunkSize,85- );86-$this->assertTrue($selectionList3->isFullChunk());87 }143 }88}144}</selection>” selected. Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
You said
I’m on page “<tabTitle>JY-20808 low priority indexing queue by Vasil-Jimi</tabTitle>” with “<selection>@@ -5,84 +5,140 @@5namespace Tests\Unit\Component\ES\Processor\DTOs;5namespace Tests\Unit\Component\ES\Processor\DTOs;667use Jiminny\Component\ES\Processor\DTOs\SelectionList;7use Jiminny\Component\ES\Processor\DTOs\SelectionList;8+use Jiminny\Component\ES\QueuePriorityEnum;8use PHPUnit\Framework\Attributes\CoversClass;9use PHPUnit\Framework\Attributes\CoversClass;9use PHPUnit\Framework\TestCase;10use PHPUnit\Framework\TestCase;101111#[CoversClass(SelectionList::class)]12#[CoversClass(SelectionList::class)]12final class SelectionListTest extends TestCase13final class SelectionListTest extends TestCase13{14{14-public function testGetEntityIds(): void15+private const int CHUNK_SIZE = 100;16+17+public function testAddEntityListAndGetAllIds(): void18+ {19+$selectionList = new SelectionList();20+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);21+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);22+23+$this->assertSame([1, 2, 3, 4], $selectionList->getAllIds());24+ }25+26+public function testAddEntityListMergesMultipleCallsForSamePriority(): void27+ {28+$selectionList = new SelectionList();29+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);30+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [3, 4]);31+32+$this->assertSame([1, 2, 3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));33+ }34+35+public function testGetEntityListItemsByGroup(): void36+ {37+$selectionList = new SelectionList();38+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);39+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);40+$selectionList->addEntityList(QueuePriorityEnum::LOW, [5, 6]);41+42+$this->assertSame([1, 2], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));43+$this->assertSame([3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::NORMAL));44+$this->assertSame([5, 6], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::LOW));45+ }46+47+public function testGetEntityListItemsByGroupReturnsEmptyArrayForUnknownGroup(): void15 {48 {16-$priority = ['p1', 'p2'];49+$selectionList = new SelectionList();17-$normal = ['n1', 'n2'];50+18-$selectionList = new SelectionList($priority, $normal);51+$this->assertSame([], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));52+ }195320-$this->assertSame($priority, $selectionList->getHighPriorityEntityIds());54+public function testGetEntityListGroups(): void21-$this->assertSame($normal, $selectionList->getNormalPriorityEntityId());55+ {56+$selectionList = new SelectionList();57+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);58+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2]);225923-$this->assertSame(['p1', 'p2', 'n1', 'n2'], $selectionList->getAllIds());60+$this->assertSame(['high', 'normal'], $selectionList->getEntityListGroups());24 }61 }256226public function testCountReturnsTotalCount(): void63public function testCountReturnsTotalCount(): void27 {64 {28-$selectionList = new SelectionList(['p1'], ['n1', 'n2']);65+$selectionList = new SelectionList();66+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);67+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2, 3]);68+29$this->assertSame(3, $selectionList->count());69$this->assertSame(3, $selectionList->count());30 }70 }317132-public function testIsEmptyReturnsTrueWhenBothListsAreEmpty(): void72+public function testIsEmptyReturnsTrueWhenNoEntitiesAdded(): void33 {73 {34-$selectionList = new SelectionList([], []);74+$selectionList = new SelectionList();75+35$this->assertTrue($selectionList->isEmpty());76$this->assertTrue($selectionList->isEmpty());36 }77 }377838-public function testIsEmptyReturnsFalseWhenAnyListIsNotEmpty(): void79+public function testIsEmptyReturnsFalseWhenEntitiesAdded(): void39 {80 {40-$selectionList = new SelectionList(['p1'], []);81+$selectionList = new SelectionList();41-$this->assertFalse($selectionList->isEmpty());82+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);428343-$selectionList2 = new SelectionList([], ['n1']);84+$this->assertFalse($selectionList->isEmpty());44-$this->assertFalse($selectionList2->isEmpty());45 }85 }468647-public function testIsStaleChunkSelected(): void87+public function testMarkStaleAndIsStaleChunkSelected(): void48 {88 {49-$selectionList = new SelectionList([], [], true);89+$selectionList = new SelectionList();50-$this->assertTrue($selectionList->isStaleChunkSelected());90+91+$this->assertFalse($selectionList->isStaleChunkSelected());92+93+$selectionList->markStale();519452-$selectionList2 = new SelectionList([], [], false);95+$this->assertTrue($selectionList->isStaleChunkSelected());53-$this->assertFalse($selectionList2->isStaleChunkSelected());54 }96 }559756public function testIsFullChunk(): void98public function testIsFullChunk(): void57 {99 {58-$chunkSize = 200;100+$selectionList = new SelectionList();59-101+$selectionList->setChunkSize(self::CHUNK_SIZE);60-$fullList = range(1, $chunkSize);102+61-$selectionList = new SelectionList(103+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, self::CHUNK_SIZE));62- priorityEntityIdList: $fullList,104+63- normalEntityIdList: [],105+$this->assertTrue($selectionList->isFullChunk());64- chunkSize: $chunkSize,106+ }65- );107+108+public function testIsNotFullChunkWhenBelowChunkSize(): void109+ {110+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);111+112+$selectionList = new SelectionList();113+$selectionList->setChunkSize(self::CHUNK_SIZE);114+115+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range(1, $halfRange));116+117+$this->assertFalse($selectionList->isFullChunk());118+ }119+120+public function testIsFullChunkAcrossMultiplePriorityGroups(): void121+ {122+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);123+124+$selectionList = new SelectionList();125+$selectionList->setChunkSize(self::CHUNK_SIZE);126+127+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, $halfRange));128+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range($halfRange + 1, self::CHUNK_SIZE));129+130+$this->assertTrue($selectionList->isFullChunk());131+ }132+133+public function testSetChunkSizeAffectsIsFullChunk(): void134+ {135+$selectionList = new SelectionList();136+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [1, 2, 3]);137+138+$selectionList->setChunkSize(3);66$this->assertTrue($selectionList->isFullChunk());139$this->assertTrue($selectionList->isFullChunk());6714068-$halfRange = (int) ceil($chunkSize / 2);141+$selectionList->setChunkSize(50);69-142+$this->assertFalse($selectionList->isFullChunk());70-$notFullList = range(1, $halfRange);71-$selectionList2 = new SelectionList(72- priorityEntityIdList: $notFullList,73- normalEntityIdList: [],74- chunkSize: $chunkSize,75- );76-$this->assertFalse($selectionList2->isFullChunk());77-78-$priorityRange = range(1, $halfRange);79-$normalRange = range($halfRange + 1, $chunkSize);80-81-$selectionList3 = new SelectionList(82- priorityEntityIdList: $priorityRange,83- normalEntityIdList: $normalRange,84- chunkSize: $chunkSize,85- );86-$this->assertTrue($selectionList3->isFullChunk());87 }143 }88}144}</selection>” selected.
Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
Expand
Listen
Gemini said
Gemini said
Here is a precise and concise summary of the code selection, which refactors
SelectionListTest
to accommodate a shift from fixed high/normal priority properties to a more dynamic, enum-driven priority group architecture.
Refactored Priority Handling
Refactored Priority Handling
Dynamic Priority Groups:
Replaces fixed high/normal array parameters with the
QueuePriorityEnum
(
HIGH
,
NORMAL
,
LOW
), allowing entity lists to be managed dynamically by group types.
Merged Registrations:
Validates that multiple
addEntityList()
calls targeting the same priority level properly merge their data instead of overwriting it.
Group Querying:
Tests new methods
getEntityListItemsByGroup()
and
getEntityListGroups()
to retrieve group-specific IDs or an array of active group names (e.g.,
['high', 'normal']
).
Updated State and Count Validations
Updated State and Count Validations
Instantiation:
Tests now instantiate
SelectionList
without initial constructor arguments, using setters and action methods instead.
Empty States:
Updates assertions (
isEmpty()
) to verify state based on whether any entities have been dynamically added, rather than checking pre-defined constructor arrays.
Stale Flags:
Changes from passing a
stale
boolean via the constructor to explicitly triggering a mutable
$selectionList->markStale()
method.
Chunk Capacity Behavior
Chunk Capacity Behavior
Flexible Chunk Sizes:
Introduces a
setChunkSize()
method, replacing the constructor-configured chunk boundary.
Capacity Assertions:
Retains and updates the logic for
isFullChunk()
, ensuring it accurately evaluates capacity when elements span multiple dynamic priority groups or when the chunk limit is altered mid-lifecycle.
Good response
Bad response
Share & export
Copy
Show more options
Copy prompt
You said Are there any issues or potential bolltenecks
You said
Are there any issues or potential bolltenecks
Listen
Show thinking
Gemini said
Gemini said
Based on the test diff you provided, we can infer a few potential issues and architectural bottlenecks in the underlying
SelectionList
implementation. While the tests are well-structured, the behavior they describe hints at a few areas you might want to keep an eye on, particularly for an Elasticsearch (ES) processor queue.
Here are the potential issues and bottlenecks to consider:
1. Array Merging Overhead (Performance)
1. Array Merging Overhead (Performance)
The
testAddEntityListMergesMultipleCallsForSamePriority
test shows that calling
addEntityList()
multiple times for the same priority group merges the arrays.
The Bottleneck:
If the underlying implementation uses
array_merge()
inside a loop to append these IDs, it creates a new array in memory every time it's called. If you are processing thousands of entities and appending them in small batches, this can lead to memory bloat and CPU degradation due to constant array reallocation.
Mitigation:
Ensure the implementation handles batch appends efficiently (e.g., using the spread operator
[...$existing, ...$new]
or appending via references) or groups the arrays before doing a single merge.
2. Lack of Uniqueness/Deduplication (Logic)
2. Lack of Uniqueness/Deduplication (Logic)
None of the tests explicitly verify what happens if duplicate IDs are added. For example, if you call
addEntityList(QueuePriorityEnum::HIGH, [1, 2])
and then
addEntityList(QueuePriorityEnum::HIGH, [2, 3])
.
The Issue:
Does the getter return
[1, 2, 2, 3]
or
[1, 2, 3]
? If duplicates are not filtered out, your ES processor might end up indexing the same entity multiple times in a single chunk, which wastes I/O and processor cycles.
Mitigation:
The underlying class should ideally enforce uniqueness (e.g., using
array_unique()
before resolving the chunk, or using ID keys as associative array keys to naturally prevent duplicates).
3. Memory Consumption with Large Chunks (Scalability)
3. Memory Consumption with Large Chunks (Scalability)
The tests introduce
setChunkSize()
. If this chunk size is configured to be very large (e.g., tens of thousands of IDs to bulk-send to Elasticsearch).
The Bottleneck:
Holding massive arrays of IDs in memory across different priority groups can quickly hit PHP memory limits, especially if this
SelectionList
object is kept alive during a long-running daemon or cron job.
Mitigation:
Monitor memory usage if
CHUNK_SIZE
grows, and ensure the...
|
[{"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":"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 I’m on page “<tabTitle>JY-20808 low priority indexing queue by Vasil-Jimi</tabTitle>” with “<selection>@@ -5,84 +5,140 @@5namespace Tests\\Unit\\Component\\ES\\Processor\\DTOs;5namespace Tests\\Unit\\Component\\ES\\Processor\\DTOs;667use Jiminny\\Component\\ES\\Processor\\DTOs\\SelectionList;7use Jiminny\\Component\\ES\\Processor\\DTOs\\SelectionList;8+use Jiminny\\Component\\ES\\QueuePriorityEnum;8use PHPUnit\\Framework\\Attributes\\CoversClass;9use PHPUnit\\Framework\\Attributes\\CoversClass;9use PHPUnit\\Framework\\TestCase;10use PHPUnit\\Framework\\TestCase;101111#[CoversClass(SelectionList::class)]12#[CoversClass(SelectionList::class)]12final class SelectionListTest extends TestCase13final class SelectionListTest extends TestCase13{14{14-public function testGetEntityIds(): void15+private const int CHUNK_SIZE = 100;16+17+public function testAddEntityListAndGetAllIds(): void18+ {19+$selectionList = new SelectionList();20+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);21+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);22+23+$this->assertSame([1, 2, 3, 4], $selectionList->getAllIds());24+ }25+26+public function testAddEntityListMergesMultipleCallsForSamePriority(): void27+ {28+$selectionList = new SelectionList();29+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);30+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [3, 4]);31+32+$this->assertSame([1, 2, 3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));33+ }34+35+public function testGetEntityListItemsByGroup(): void36+ {37+$selectionList = new SelectionList();38+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);39+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);40+$selectionList->addEntityList(QueuePriorityEnum::LOW, [5, 6]);41+42+$this->assertSame([1, 2], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));43+$this->assertSame([3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::NORMAL));44+$this->assertSame([5, 6], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::LOW));45+ }46+47+public function testGetEntityListItemsByGroupReturnsEmptyArrayForUnknownGroup(): void15 {48 {16-$priority = ['p1', 'p2'];49+$selectionList = new SelectionList();17-$normal = ['n1', 'n2'];50+18-$selectionList = new SelectionList($priority, $normal);51+$this->assertSame([], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));52+ }195320-$this->assertSame($priority, $selectionList->getHighPriorityEntityIds());54+public function testGetEntityListGroups(): void21-$this->assertSame($normal, $selectionList->getNormalPriorityEntityId());55+ {56+$selectionList = new SelectionList();57+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);58+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2]);225923-$this->assertSame(['p1', 'p2', 'n1', 'n2'], $selectionList->getAllIds());60+$this->assertSame(['high', 'normal'], $selectionList->getEntityListGroups());24 }61 }256226public function testCountReturnsTotalCount(): void63public function testCountReturnsTotalCount(): void27 {64 {28-$selectionList = new SelectionList(['p1'], ['n1', 'n2']);65+$selectionList = new SelectionList();66+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);67+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2, 3]);68+29$this->assertSame(3, $selectionList->count());69$this->assertSame(3, $selectionList->count());30 }70 }317132-public function testIsEmptyReturnsTrueWhenBothListsAreEmpty(): void72+public function testIsEmptyReturnsTrueWhenNoEntitiesAdded(): void33 {73 {34-$selectionList = new SelectionList([], []);74+$selectionList = new SelectionList();75+35$this->assertTrue($selectionList->isEmpty());76$this->assertTrue($selectionList->isEmpty());36 }77 }377838-public function testIsEmptyReturnsFalseWhenAnyListIsNotEmpty(): void79+public function testIsEmptyReturnsFalseWhenEntitiesAdded(): void39 {80 {40-$selectionList = new SelectionList(['p1'], []);81+$selectionList = new SelectionList();41-$this->assertFalse($selectionList->isEmpty());82+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);428343-$selectionList2 = new SelectionList([], ['n1']);84+$this->assertFalse($selectionList->isEmpty());44-$this->assertFalse($selectionList2->isEmpty());45 }85 }468647-public function testIsStaleChunkSelected(): void87+public function testMarkStaleAndIsStaleChunkSelected(): void48 {88 {49-$selectionList = new SelectionList([], [], true);89+$selectionList = new SelectionList();50-$this->assertTrue($selectionList->isStaleChunkSelected());90+91+$this->assertFalse($selectionList->isStaleChunkSelected());92+93+$selectionList->markStale();519452-$selectionList2 = new SelectionList([], [], false);95+$this->assertTrue($selectionList->isStaleChunkSelected());53-$this->assertFalse($selectionList2->isStaleChunkSelected());54 }96 }559756public function testIsFullChunk(): void98public function testIsFullChunk(): void57 {99 {58-$chunkSize = 200;100+$selectionList = new SelectionList();59-101+$selectionList->setChunkSize(self::CHUNK_SIZE);60-$fullList = range(1, $chunkSize);102+61-$selectionList = new SelectionList(103+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, self::CHUNK_SIZE));62- priorityEntityIdList: $fullList,104+63- normalEntityIdList: [],105+$this->assertTrue($selectionList->isFullChunk());64- chunkSize: $chunkSize,106+ }65- );107+108+public function testIsNotFullChunkWhenBelowChunkSize(): void109+ {110+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);111+112+$selectionList = new SelectionList();113+$selectionList->setChunkSize(self::CHUNK_SIZE);114+115+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range(1, $halfRange));116+117+$this->assertFalse($selectionList->isFullChunk());118+ }119+120+public function testIsFullChunkAcrossMultiplePriorityGroups(): void121+ {122+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);123+124+$selectionList = new SelectionList();125+$selectionList->setChunkSize(self::CHUNK_SIZE);126+127+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, $halfRange));128+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range($halfRange + 1, self::CHUNK_SIZE));129+130+$this->assertTrue($selectionList->isFullChunk());131+ }132+133+public function testSetChunkSizeAffectsIsFullChunk(): void134+ {135+$selectionList = new SelectionList();136+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [1, 2, 3]);137+138+$selectionList->setChunkSize(3);66$this->assertTrue($selectionList->isFullChunk());139$this->assertTrue($selectionList->isFullChunk());6714068-$halfRange = (int) ceil($chunkSize / 2);141+$selectionList->setChunkSize(50);69-142+$this->assertFalse($selectionList->isFullChunk());70-$notFullList = range(1, $halfRange);71-$selectionList2 = new SelectionList(72- priorityEntityIdList: $notFullList,73- normalEntityIdList: [],74- chunkSize: $chunkSize,75- );76-$this->assertFalse($selectionList2->isFullChunk());77-78-$priorityRange = range(1, $halfRange);79-$normalRange = range($halfRange + 1, $chunkSize);80-81-$selectionList3 = new SelectionList(82- priorityEntityIdList: $priorityRange,83- normalEntityIdList: $normalRange,84- chunkSize: $chunkSize,85- );86-$this->assertTrue($selectionList3->isFullChunk());87 }143 }88}144}</selection>” selected. Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.","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":"I’m on page “<tabTitle>JY-20808 low priority indexing queue by Vasil-Jimi</tabTitle>” with “<selection>@@ -5,84 +5,140 @@5namespace Tests\\Unit\\Component\\ES\\Processor\\DTOs;5namespace Tests\\Unit\\Component\\ES\\Processor\\DTOs;667use Jiminny\\Component\\ES\\Processor\\DTOs\\SelectionList;7use Jiminny\\Component\\ES\\Processor\\DTOs\\SelectionList;8+use Jiminny\\Component\\ES\\QueuePriorityEnum;8use PHPUnit\\Framework\\Attributes\\CoversClass;9use PHPUnit\\Framework\\Attributes\\CoversClass;9use PHPUnit\\Framework\\TestCase;10use PHPUnit\\Framework\\TestCase;101111#[CoversClass(SelectionList::class)]12#[CoversClass(SelectionList::class)]12final class SelectionListTest extends TestCase13final class SelectionListTest extends TestCase13{14{14-public function testGetEntityIds(): void15+private const int CHUNK_SIZE = 100;16+17+public function testAddEntityListAndGetAllIds(): void18+ {19+$selectionList = new SelectionList();20+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);21+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);22+23+$this->assertSame([1, 2, 3, 4], $selectionList->getAllIds());24+ }25+26+public function testAddEntityListMergesMultipleCallsForSamePriority(): void27+ {28+$selectionList = new SelectionList();29+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);30+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [3, 4]);31+32+$this->assertSame([1, 2, 3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));33+ }34+35+public function testGetEntityListItemsByGroup(): void36+ {37+$selectionList = new SelectionList();38+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);39+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);40+$selectionList->addEntityList(QueuePriorityEnum::LOW, [5, 6]);41+42+$this->assertSame([1, 2], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));43+$this->assertSame([3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::NORMAL));44+$this->assertSame([5, 6], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::LOW));45+ }46+47+public function testGetEntityListItemsByGroupReturnsEmptyArrayForUnknownGroup(): void15 {48 {16-$priority = ['p1', 'p2'];49+$selectionList = new SelectionList();17-$normal = ['n1', 'n2'];50+18-$selectionList = new SelectionList($priority, $normal);51+$this->assertSame([], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));52+ }195320-$this->assertSame($priority, $selectionList->getHighPriorityEntityIds());54+public function testGetEntityListGroups(): void21-$this->assertSame($normal, $selectionList->getNormalPriorityEntityId());55+ {56+$selectionList = new SelectionList();57+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);58+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2]);225923-$this->assertSame(['p1', 'p2', 'n1', 'n2'], $selectionList->getAllIds());60+$this->assertSame(['high', 'normal'], $selectionList->getEntityListGroups());24 }61 }256226public function testCountReturnsTotalCount(): void63public function testCountReturnsTotalCount(): void27 {64 {28-$selectionList = new SelectionList(['p1'], ['n1', 'n2']);65+$selectionList = new SelectionList();66+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);67+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2, 3]);68+29$this->assertSame(3, $selectionList->count());69$this->assertSame(3, $selectionList->count());30 }70 }317132-public function testIsEmptyReturnsTrueWhenBothListsAreEmpty(): void72+public function testIsEmptyReturnsTrueWhenNoEntitiesAdded(): void33 {73 {34-$selectionList = new SelectionList([], []);74+$selectionList = new SelectionList();75+35$this->assertTrue($selectionList->isEmpty());76$this->assertTrue($selectionList->isEmpty());36 }77 }377838-public function testIsEmptyReturnsFalseWhenAnyListIsNotEmpty(): void79+public function testIsEmptyReturnsFalseWhenEntitiesAdded(): void39 {80 {40-$selectionList = new SelectionList(['p1'], []);81+$selectionList = new SelectionList();41-$this->assertFalse($selectionList->isEmpty());82+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);428343-$selectionList2 = new SelectionList([], ['n1']);84+$this->assertFalse($selectionList->isEmpty());44-$this->assertFalse($selectionList2->isEmpty());45 }85 }468647-public function testIsStaleChunkSelected(): void87+public function testMarkStaleAndIsStaleChunkSelected(): void48 {88 {49-$selectionList = new SelectionList([], [], true);89+$selectionList = new SelectionList();50-$this->assertTrue($selectionList->isStaleChunkSelected());90+91+$this->assertFalse($selectionList->isStaleChunkSelected());92+93+$selectionList->markStale();519452-$selectionList2 = new SelectionList([], [], false);95+$this->assertTrue($selectionList->isStaleChunkSelected());53-$this->assertFalse($selectionList2->isStaleChunkSelected());54 }96 }559756public function testIsFullChunk(): void98public function testIsFullChunk(): void57 {99 {58-$chunkSize = 200;100+$selectionList = new SelectionList();59-101+$selectionList->setChunkSize(self::CHUNK_SIZE);60-$fullList = range(1, $chunkSize);102+61-$selectionList = new SelectionList(103+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, self::CHUNK_SIZE));62- priorityEntityIdList: $fullList,104+63- normalEntityIdList: [],105+$this->assertTrue($selectionList->isFullChunk());64- chunkSize: $chunkSize,106+ }65- );107+108+public function testIsNotFullChunkWhenBelowChunkSize(): void109+ {110+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);111+112+$selectionList = new SelectionList();113+$selectionList->setChunkSize(self::CHUNK_SIZE);114+115+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range(1, $halfRange));116+117+$this->assertFalse($selectionList->isFullChunk());118+ }119+120+public function testIsFullChunkAcrossMultiplePriorityGroups(): void121+ {122+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);123+124+$selectionList = new SelectionList();125+$selectionList->setChunkSize(self::CHUNK_SIZE);126+127+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, $halfRange));128+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range($halfRange + 1, self::CHUNK_SIZE));129+130+$this->assertTrue($selectionList->isFullChunk());131+ }132+133+public function testSetChunkSizeAffectsIsFullChunk(): void134+ {135+$selectionList = new SelectionList();136+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [1, 2, 3]);137+138+$selectionList->setChunkSize(3);66$this->assertTrue($selectionList->isFullChunk());139$this->assertTrue($selectionList->isFullChunk());6714068-$halfRange = (int) ceil($chunkSize / 2);141+$selectionList->setChunkSize(50);69-142+$this->assertFalse($selectionList->isFullChunk());70-$notFullList = range(1, $halfRange);71-$selectionList2 = new SelectionList(72- priorityEntityIdList: $notFullList,73- normalEntityIdList: [],74- chunkSize: $chunkSize,75- );76-$this->assertFalse($selectionList2->isFullChunk());77-78-$priorityRange = range(1, $halfRange);79-$normalRange = range($halfRange + 1, $chunkSize);80-81-$selectionList3 = new SelectionList(82- priorityEntityIdList: $priorityRange,83- normalEntityIdList: $normalRange,84- chunkSize: $chunkSize,85- );86-$this->assertTrue($selectionList3->isFullChunk());87 }143 }88}144}</selection>” selected.","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Expand","depth":21,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"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":"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":"Here is a precise and concise summary of the code selection, which refactors","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SelectionListTest","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"to accommodate a shift from fixed high/normal priority properties to a more dynamic, enum-driven priority group architecture.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Refactored Priority Handling","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Refactored Priority Handling","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Dynamic Priority Groups:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Replaces fixed high/normal array parameters with the","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"QueuePriorityEnum","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"HIGH","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"NORMAL","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"LOW","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"), allowing entity lists to be managed dynamically by group types.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Merged Registrations:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Validates that multiple","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"addEntityList()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"calls targeting the same priority level properly merge their data instead of overwriting it.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Group Querying:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Tests new methods","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"getEntityListItemsByGroup()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"and","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"getEntityListGroups()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"to retrieve group-specific IDs or an array of active group names (e.g.,","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"['high', 'normal']","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":").","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Updated State and Count Validations","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Updated State and Count Validations","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Instantiation:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Tests now instantiate","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SelectionList","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"without initial constructor arguments, using setters and action methods instead.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Empty States:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Updates assertions (","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"isEmpty()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":") to verify state based on whether any entities have been dynamically added, rather than checking pre-defined constructor arrays.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Stale Flags:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Changes from passing a","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"stale","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"boolean via the constructor to explicitly triggering a mutable","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$selectionList->markStale()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"method.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Chunk Capacity Behavior","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Chunk Capacity Behavior","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Flexible Chunk Sizes:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Introduces a","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"setChunkSize()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"method, replacing the constructor-configured chunk boundary.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Capacity Assertions:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Retains and updates the logic for","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"isFullChunk()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":", ensuring it accurately evaluates capacity when elements span multiple dynamic priority groups or when the chunk limit is altered mid-lifecycle.","depth":26,"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":"AXHeading","text":"You said Are there any issues or potential bolltenecks","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":"Are there any issues or potential bolltenecks","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":"Based on the test diff you provided, we can infer a few potential issues and architectural bottlenecks in the underlying","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SelectionList","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"implementation. While the tests are well-structured, the behavior they describe hints at a few areas you might want to keep an eye on, particularly for an Elasticsearch (ES) processor queue.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Here are the potential issues and bottlenecks to consider:","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"1. Array Merging Overhead (Performance)","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1. Array Merging Overhead (Performance)","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"testAddEntityListMergesMultipleCallsForSamePriority","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"test shows that calling","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"addEntityList()","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"multiple times for the same priority group merges the arrays.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The Bottleneck:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"If the underlying implementation uses","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"array_merge()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"inside a loop to append these IDs, it creates a new array in memory every time it's called. If you are processing thousands of entities and appending them in small batches, this can lead to memory bloat and CPU degradation due to constant array reallocation.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Mitigation:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Ensure the implementation handles batch appends efficiently (e.g., using the spread operator","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"[...$existing, ...$new]","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"or appending via references) or groups the arrays before doing a single merge.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"2. Lack of Uniqueness/Deduplication (Logic)","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2. Lack of Uniqueness/Deduplication (Logic)","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"None of the tests explicitly verify what happens if duplicate IDs are added. For example, if you call","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"addEntityList(QueuePriorityEnum::HIGH, [1, 2])","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"and then","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"addEntityList(QueuePriorityEnum::HIGH, [2, 3])","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":".","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The Issue:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Does the getter return","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"[1, 2, 2, 3]","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"or","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"[1, 2, 3]","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"? If duplicates are not filtered out, your ES processor might end up indexing the same entity multiple times in a single chunk, which wastes I/O and processor cycles.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Mitigation:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The underlying class should ideally enforce uniqueness (e.g., using","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"array_unique()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"before resolving the chunk, or using ID keys as associative array keys to naturally prevent duplicates).","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"3. Memory Consumption with Large Chunks (Scalability)","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3. Memory Consumption with Large Chunks (Scalability)","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The tests introduce","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"setChunkSize()","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":". If this chunk size is configured to be very large (e.g., tens of thousands of IDs to bulk-send to Elasticsearch).","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The Bottleneck:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Holding massive arrays of IDs in memory across different priority groups can quickly hit PHP memory limits, especially if this","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SelectionList","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"object is kept alive during a long-running daemon or cron job.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Mitigation:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Monitor memory usage if","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"CHUNK_SIZE","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"grows, and ensure the","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"}]...
|
-4510348526296732241
|
8165667213393097111
|
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
Copy prompt
You said I’m on page “<tabTitle>JY-20808 low priority indexing queue by Vasil-Jimi</tabTitle>” with “<selection>@@ -5,84 +5,140 @@5namespace Tests\Unit\Component\ES\Processor\DTOs;5namespace Tests\Unit\Component\ES\Processor\DTOs;667use Jiminny\Component\ES\Processor\DTOs\SelectionList;7use Jiminny\Component\ES\Processor\DTOs\SelectionList;8+use Jiminny\Component\ES\QueuePriorityEnum;8use PHPUnit\Framework\Attributes\CoversClass;9use PHPUnit\Framework\Attributes\CoversClass;9use PHPUnit\Framework\TestCase;10use PHPUnit\Framework\TestCase;101111#[CoversClass(SelectionList::class)]12#[CoversClass(SelectionList::class)]12final class SelectionListTest extends TestCase13final class SelectionListTest extends TestCase13{14{14-public function testGetEntityIds(): void15+private const int CHUNK_SIZE = 100;16+17+public function testAddEntityListAndGetAllIds(): void18+ {19+$selectionList = new SelectionList();20+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);21+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);22+23+$this->assertSame([1, 2, 3, 4], $selectionList->getAllIds());24+ }25+26+public function testAddEntityListMergesMultipleCallsForSamePriority(): void27+ {28+$selectionList = new SelectionList();29+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);30+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [3, 4]);31+32+$this->assertSame([1, 2, 3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));33+ }34+35+public function testGetEntityListItemsByGroup(): void36+ {37+$selectionList = new SelectionList();38+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);39+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);40+$selectionList->addEntityList(QueuePriorityEnum::LOW, [5, 6]);41+42+$this->assertSame([1, 2], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));43+$this->assertSame([3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::NORMAL));44+$this->assertSame([5, 6], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::LOW));45+ }46+47+public function testGetEntityListItemsByGroupReturnsEmptyArrayForUnknownGroup(): void15 {48 {16-$priority = ['p1', 'p2'];49+$selectionList = new SelectionList();17-$normal = ['n1', 'n2'];50+18-$selectionList = new SelectionList($priority, $normal);51+$this->assertSame([], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));52+ }195320-$this->assertSame($priority, $selectionList->getHighPriorityEntityIds());54+public function testGetEntityListGroups(): void21-$this->assertSame($normal, $selectionList->getNormalPriorityEntityId());55+ {56+$selectionList = new SelectionList();57+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);58+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2]);225923-$this->assertSame(['p1', 'p2', 'n1', 'n2'], $selectionList->getAllIds());60+$this->assertSame(['high', 'normal'], $selectionList->getEntityListGroups());24 }61 }256226public function testCountReturnsTotalCount(): void63public function testCountReturnsTotalCount(): void27 {64 {28-$selectionList = new SelectionList(['p1'], ['n1', 'n2']);65+$selectionList = new SelectionList();66+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);67+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2, 3]);68+29$this->assertSame(3, $selectionList->count());69$this->assertSame(3, $selectionList->count());30 }70 }317132-public function testIsEmptyReturnsTrueWhenBothListsAreEmpty(): void72+public function testIsEmptyReturnsTrueWhenNoEntitiesAdded(): void33 {73 {34-$selectionList = new SelectionList([], []);74+$selectionList = new SelectionList();75+35$this->assertTrue($selectionList->isEmpty());76$this->assertTrue($selectionList->isEmpty());36 }77 }377838-public function testIsEmptyReturnsFalseWhenAnyListIsNotEmpty(): void79+public function testIsEmptyReturnsFalseWhenEntitiesAdded(): void39 {80 {40-$selectionList = new SelectionList(['p1'], []);81+$selectionList = new SelectionList();41-$this->assertFalse($selectionList->isEmpty());82+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);428343-$selectionList2 = new SelectionList([], ['n1']);84+$this->assertFalse($selectionList->isEmpty());44-$this->assertFalse($selectionList2->isEmpty());45 }85 }468647-public function testIsStaleChunkSelected(): void87+public function testMarkStaleAndIsStaleChunkSelected(): void48 {88 {49-$selectionList = new SelectionList([], [], true);89+$selectionList = new SelectionList();50-$this->assertTrue($selectionList->isStaleChunkSelected());90+91+$this->assertFalse($selectionList->isStaleChunkSelected());92+93+$selectionList->markStale();519452-$selectionList2 = new SelectionList([], [], false);95+$this->assertTrue($selectionList->isStaleChunkSelected());53-$this->assertFalse($selectionList2->isStaleChunkSelected());54 }96 }559756public function testIsFullChunk(): void98public function testIsFullChunk(): void57 {99 {58-$chunkSize = 200;100+$selectionList = new SelectionList();59-101+$selectionList->setChunkSize(self::CHUNK_SIZE);60-$fullList = range(1, $chunkSize);102+61-$selectionList = new SelectionList(103+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, self::CHUNK_SIZE));62- priorityEntityIdList: $fullList,104+63- normalEntityIdList: [],105+$this->assertTrue($selectionList->isFullChunk());64- chunkSize: $chunkSize,106+ }65- );107+108+public function testIsNotFullChunkWhenBelowChunkSize(): void109+ {110+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);111+112+$selectionList = new SelectionList();113+$selectionList->setChunkSize(self::CHUNK_SIZE);114+115+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range(1, $halfRange));116+117+$this->assertFalse($selectionList->isFullChunk());118+ }119+120+public function testIsFullChunkAcrossMultiplePriorityGroups(): void121+ {122+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);123+124+$selectionList = new SelectionList();125+$selectionList->setChunkSize(self::CHUNK_SIZE);126+127+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, $halfRange));128+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range($halfRange + 1, self::CHUNK_SIZE));129+130+$this->assertTrue($selectionList->isFullChunk());131+ }132+133+public function testSetChunkSizeAffectsIsFullChunk(): void134+ {135+$selectionList = new SelectionList();136+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [1, 2, 3]);137+138+$selectionList->setChunkSize(3);66$this->assertTrue($selectionList->isFullChunk());139$this->assertTrue($selectionList->isFullChunk());6714068-$halfRange = (int) ceil($chunkSize / 2);141+$selectionList->setChunkSize(50);69-142+$this->assertFalse($selectionList->isFullChunk());70-$notFullList = range(1, $halfRange);71-$selectionList2 = new SelectionList(72- priorityEntityIdList: $notFullList,73- normalEntityIdList: [],74- chunkSize: $chunkSize,75- );76-$this->assertFalse($selectionList2->isFullChunk());77-78-$priorityRange = range(1, $halfRange);79-$normalRange = range($halfRange + 1, $chunkSize);80-81-$selectionList3 = new SelectionList(82- priorityEntityIdList: $priorityRange,83- normalEntityIdList: $normalRange,84- chunkSize: $chunkSize,85- );86-$this->assertTrue($selectionList3->isFullChunk());87 }143 }88}144}</selection>” selected. Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
You said
I’m on page “<tabTitle>JY-20808 low priority indexing queue by Vasil-Jimi</tabTitle>” with “<selection>@@ -5,84 +5,140 @@5namespace Tests\Unit\Component\ES\Processor\DTOs;5namespace Tests\Unit\Component\ES\Processor\DTOs;667use Jiminny\Component\ES\Processor\DTOs\SelectionList;7use Jiminny\Component\ES\Processor\DTOs\SelectionList;8+use Jiminny\Component\ES\QueuePriorityEnum;8use PHPUnit\Framework\Attributes\CoversClass;9use PHPUnit\Framework\Attributes\CoversClass;9use PHPUnit\Framework\TestCase;10use PHPUnit\Framework\TestCase;101111#[CoversClass(SelectionList::class)]12#[CoversClass(SelectionList::class)]12final class SelectionListTest extends TestCase13final class SelectionListTest extends TestCase13{14{14-public function testGetEntityIds(): void15+private const int CHUNK_SIZE = 100;16+17+public function testAddEntityListAndGetAllIds(): void18+ {19+$selectionList = new SelectionList();20+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);21+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);22+23+$this->assertSame([1, 2, 3, 4], $selectionList->getAllIds());24+ }25+26+public function testAddEntityListMergesMultipleCallsForSamePriority(): void27+ {28+$selectionList = new SelectionList();29+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);30+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [3, 4]);31+32+$this->assertSame([1, 2, 3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));33+ }34+35+public function testGetEntityListItemsByGroup(): void36+ {37+$selectionList = new SelectionList();38+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);39+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);40+$selectionList->addEntityList(QueuePriorityEnum::LOW, [5, 6]);41+42+$this->assertSame([1, 2], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));43+$this->assertSame([3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::NORMAL));44+$this->assertSame([5, 6], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::LOW));45+ }46+47+public function testGetEntityListItemsByGroupReturnsEmptyArrayForUnknownGroup(): void15 {48 {16-$priority = ['p1', 'p2'];49+$selectionList = new SelectionList();17-$normal = ['n1', 'n2'];50+18-$selectionList = new SelectionList($priority, $normal);51+$this->assertSame([], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));52+ }195320-$this->assertSame($priority, $selectionList->getHighPriorityEntityIds());54+public function testGetEntityListGroups(): void21-$this->assertSame($normal, $selectionList->getNormalPriorityEntityId());55+ {56+$selectionList = new SelectionList();57+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);58+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2]);225923-$this->assertSame(['p1', 'p2', 'n1', 'n2'], $selectionList->getAllIds());60+$this->assertSame(['high', 'normal'], $selectionList->getEntityListGroups());24 }61 }256226public function testCountReturnsTotalCount(): void63public function testCountReturnsTotalCount(): void27 {64 {28-$selectionList = new SelectionList(['p1'], ['n1', 'n2']);65+$selectionList = new SelectionList();66+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);67+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2, 3]);68+29$this->assertSame(3, $selectionList->count());69$this->assertSame(3, $selectionList->count());30 }70 }317132-public function testIsEmptyReturnsTrueWhenBothListsAreEmpty(): void72+public function testIsEmptyReturnsTrueWhenNoEntitiesAdded(): void33 {73 {34-$selectionList = new SelectionList([], []);74+$selectionList = new SelectionList();75+35$this->assertTrue($selectionList->isEmpty());76$this->assertTrue($selectionList->isEmpty());36 }77 }377838-public function testIsEmptyReturnsFalseWhenAnyListIsNotEmpty(): void79+public function testIsEmptyReturnsFalseWhenEntitiesAdded(): void39 {80 {40-$selectionList = new SelectionList(['p1'], []);81+$selectionList = new SelectionList();41-$this->assertFalse($selectionList->isEmpty());82+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);428343-$selectionList2 = new SelectionList([], ['n1']);84+$this->assertFalse($selectionList->isEmpty());44-$this->assertFalse($selectionList2->isEmpty());45 }85 }468647-public function testIsStaleChunkSelected(): void87+public function testMarkStaleAndIsStaleChunkSelected(): void48 {88 {49-$selectionList = new SelectionList([], [], true);89+$selectionList = new SelectionList();50-$this->assertTrue($selectionList->isStaleChunkSelected());90+91+$this->assertFalse($selectionList->isStaleChunkSelected());92+93+$selectionList->markStale();519452-$selectionList2 = new SelectionList([], [], false);95+$this->assertTrue($selectionList->isStaleChunkSelected());53-$this->assertFalse($selectionList2->isStaleChunkSelected());54 }96 }559756public function testIsFullChunk(): void98public function testIsFullChunk(): void57 {99 {58-$chunkSize = 200;100+$selectionList = new SelectionList();59-101+$selectionList->setChunkSize(self::CHUNK_SIZE);60-$fullList = range(1, $chunkSize);102+61-$selectionList = new SelectionList(103+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, self::CHUNK_SIZE));62- priorityEntityIdList: $fullList,104+63- normalEntityIdList: [],105+$this->assertTrue($selectionList->isFullChunk());64- chunkSize: $chunkSize,106+ }65- );107+108+public function testIsNotFullChunkWhenBelowChunkSize(): void109+ {110+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);111+112+$selectionList = new SelectionList();113+$selectionList->setChunkSize(self::CHUNK_SIZE);114+115+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range(1, $halfRange));116+117+$this->assertFalse($selectionList->isFullChunk());118+ }119+120+public function testIsFullChunkAcrossMultiplePriorityGroups(): void121+ {122+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);123+124+$selectionList = new SelectionList();125+$selectionList->setChunkSize(self::CHUNK_SIZE);126+127+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, $halfRange));128+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range($halfRange + 1, self::CHUNK_SIZE));129+130+$this->assertTrue($selectionList->isFullChunk());131+ }132+133+public function testSetChunkSizeAffectsIsFullChunk(): void134+ {135+$selectionList = new SelectionList();136+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [1, 2, 3]);137+138+$selectionList->setChunkSize(3);66$this->assertTrue($selectionList->isFullChunk());139$this->assertTrue($selectionList->isFullChunk());6714068-$halfRange = (int) ceil($chunkSize / 2);141+$selectionList->setChunkSize(50);69-142+$this->assertFalse($selectionList->isFullChunk());70-$notFullList = range(1, $halfRange);71-$selectionList2 = new SelectionList(72- priorityEntityIdList: $notFullList,73- normalEntityIdList: [],74- chunkSize: $chunkSize,75- );76-$this->assertFalse($selectionList2->isFullChunk());77-78-$priorityRange = range(1, $halfRange);79-$normalRange = range($halfRange + 1, $chunkSize);80-81-$selectionList3 = new SelectionList(82- priorityEntityIdList: $priorityRange,83- normalEntityIdList: $normalRange,84- chunkSize: $chunkSize,85- );86-$this->assertTrue($selectionList3->isFullChunk());87 }143 }88}144}</selection>” selected.
Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
Expand
Listen
Gemini said
Gemini said
Here is a precise and concise summary of the code selection, which refactors
SelectionListTest
to accommodate a shift from fixed high/normal priority properties to a more dynamic, enum-driven priority group architecture.
Refactored Priority Handling
Refactored Priority Handling
Dynamic Priority Groups:
Replaces fixed high/normal array parameters with the
QueuePriorityEnum
(
HIGH
,
NORMAL
,
LOW
), allowing entity lists to be managed dynamically by group types.
Merged Registrations:
Validates that multiple
addEntityList()
calls targeting the same priority level properly merge their data instead of overwriting it.
Group Querying:
Tests new methods
getEntityListItemsByGroup()
and
getEntityListGroups()
to retrieve group-specific IDs or an array of active group names (e.g.,
['high', 'normal']
).
Updated State and Count Validations
Updated State and Count Validations
Instantiation:
Tests now instantiate
SelectionList
without initial constructor arguments, using setters and action methods instead.
Empty States:
Updates assertions (
isEmpty()
) to verify state based on whether any entities have been dynamically added, rather than checking pre-defined constructor arrays.
Stale Flags:
Changes from passing a
stale
boolean via the constructor to explicitly triggering a mutable
$selectionList->markStale()
method.
Chunk Capacity Behavior
Chunk Capacity Behavior
Flexible Chunk Sizes:
Introduces a
setChunkSize()
method, replacing the constructor-configured chunk boundary.
Capacity Assertions:
Retains and updates the logic for
isFullChunk()
, ensuring it accurately evaluates capacity when elements span multiple dynamic priority groups or when the chunk limit is altered mid-lifecycle.
Good response
Bad response
Share & export
Copy
Show more options
Copy prompt
You said Are there any issues or potential bolltenecks
You said
Are there any issues or potential bolltenecks
Listen
Show thinking
Gemini said
Gemini said
Based on the test diff you provided, we can infer a few potential issues and architectural bottlenecks in the underlying
SelectionList
implementation. While the tests are well-structured, the behavior they describe hints at a few areas you might want to keep an eye on, particularly for an Elasticsearch (ES) processor queue.
Here are the potential issues and bottlenecks to consider:
1. Array Merging Overhead (Performance)
1. Array Merging Overhead (Performance)
The
testAddEntityListMergesMultipleCallsForSamePriority
test shows that calling
addEntityList()
multiple times for the same priority group merges the arrays.
The Bottleneck:
If the underlying implementation uses
array_merge()
inside a loop to append these IDs, it creates a new array in memory every time it's called. If you are processing thousands of entities and appending them in small batches, this can lead to memory bloat and CPU degradation due to constant array reallocation.
Mitigation:
Ensure the implementation handles batch appends efficiently (e.g., using the spread operator
[...$existing, ...$new]
or appending via references) or groups the arrays before doing a single merge.
2. Lack of Uniqueness/Deduplication (Logic)
2. Lack of Uniqueness/Deduplication (Logic)
None of the tests explicitly verify what happens if duplicate IDs are added. For example, if you call
addEntityList(QueuePriorityEnum::HIGH, [1, 2])
and then
addEntityList(QueuePriorityEnum::HIGH, [2, 3])
.
The Issue:
Does the getter return
[1, 2, 2, 3]
or
[1, 2, 3]
? If duplicates are not filtered out, your ES processor might end up indexing the same entity multiple times in a single chunk, which wastes I/O and processor cycles.
Mitigation:
The underlying class should ideally enforce uniqueness (e.g., using
array_unique()
before resolving the chunk, or using ID keys as associative array keys to naturally prevent duplicates).
3. Memory Consumption with Large Chunks (Scalability)
3. Memory Consumption with Large Chunks (Scalability)
The tests introduce
setChunkSize()
. If this chunk size is configured to be very large (e.g., tens of thousands of IDs to bulk-send to Elasticsearch).
The Bottleneck:
Holding massive arrays of IDs in memory across different priority groups can quickly hit PHP memory limits, especially if this
SelectionList
object is kept alive during a long-running daemon or cron job.
Mitigation:
Monitor memory usage if
CHUNK_SIZE
grows, and ensure the...
|
55657
|
NULL
|
NULL
|
NULL
|
|
55660
|
NULL
|
0
|
2026-05-19T06:36:33.989578+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779172593989_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-4bd github.com/jiminny/app/pull/12082/changes#diff-4bdd02759b5e0d060dcbc8c2dcb9bdbc3d0266d9c2e29956b9d63916dae1fdd7...
|
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
Copy prompt
You said I’m on page “<tabTitle>JY-20808 low priority indexing queue by Vasil-Jimi</tabTitle>” with “<selection>@@ -5,84 +5,140 @@5namespace Tests\Unit\Component\ES\Processor\DTOs;5namespace Tests\Unit\Component\ES\Processor\DTOs;667use Jiminny\Component\ES\Processor\DTOs\SelectionList;7use Jiminny\Component\ES\Processor\DTOs\SelectionList;8+use Jiminny\Component\ES\QueuePriorityEnum;8use PHPUnit\Framework\Attributes\CoversClass;9use PHPUnit\Framework\Attributes\CoversClass;9use PHPUnit\Framework\TestCase;10use PHPUnit\Framework\TestCase;101111#[CoversClass(SelectionList::class)]12#[CoversClass(SelectionList::class)]12final class SelectionListTest extends TestCase13final class SelectionListTest extends TestCase13{14{14-public function testGetEntityIds(): void15+private const int CHUNK_SIZE = 100;16+17+public function testAddEntityListAndGetAllIds(): void18+ {19+$selectionList = new SelectionList();20+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);21+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);22+23+$this->assertSame([1, 2, 3, 4], $selectionList->getAllIds());24+ }25+26+public function testAddEntityListMergesMultipleCallsForSamePriority(): void27+ {28+$selectionList = new SelectionList();29+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);30+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [3, 4]);31+32+$this->assertSame([1, 2, 3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));33+ }34+35+public function testGetEntityListItemsByGroup(): void36+ {37+$selectionList = new SelectionList();38+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);39+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);40+$selectionList->addEntityList(QueuePriorityEnum::LOW, [5, 6]);41+42+$this->assertSame([1, 2], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));43+$this->assertSame([3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::NORMAL));44+$this->assertSame([5, 6], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::LOW));45+ }46+47+public function testGetEntityListItemsByGroupReturnsEmptyArrayForUnknownGroup(): void15 {48 {16-$priority = ['p1', 'p2'];49+$selectionList = new SelectionList();17-$normal = ['n1', 'n2'];50+18-$selectionList = new SelectionList($priority, $normal);51+$this->assertSame([], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));52+ }195320-$this->assertSame($priority, $selectionList->getHighPriorityEntityIds());54+public function testGetEntityListGroups(): void21-$this->assertSame($normal, $selectionList->getNormalPriorityEntityId());55+ {56+$selectionList = new SelectionList();57+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);58+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2]);225923-$this->assertSame(['p1', 'p2', 'n1', 'n2'], $selectionList->getAllIds());60+$this->assertSame(['high', 'normal'], $selectionList->getEntityListGroups());24 }61 }256226public function testCountReturnsTotalCount(): void63public function testCountReturnsTotalCount(): void27 {64 {28-$selectionList = new SelectionList(['p1'], ['n1', 'n2']);65+$selectionList = new SelectionList();66+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);67+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2, 3]);68+29$this->assertSame(3, $selectionList->count());69$this->assertSame(3, $selectionList->count());30 }70 }317132-public function testIsEmptyReturnsTrueWhenBothListsAreEmpty(): void72+public function testIsEmptyReturnsTrueWhenNoEntitiesAdded(): void33 {73 {34-$selectionList = new SelectionList([], []);74+$selectionList = new SelectionList();75+35$this->assertTrue($selectionList->isEmpty());76$this->assertTrue($selectionList->isEmpty());36 }77 }377838-public function testIsEmptyReturnsFalseWhenAnyListIsNotEmpty(): void79+public function testIsEmptyReturnsFalseWhenEntitiesAdded(): void39 {80 {40-$selectionList = new SelectionList(['p1'], []);81+$selectionList = new SelectionList();41-$this->assertFalse($selectionList->isEmpty());82+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);428343-$selectionList2 = new SelectionList([], ['n1']);84+$this->assertFalse($selectionList->isEmpty());44-$this->assertFalse($selectionList2->isEmpty());45 }85 }468647-public function testIsStaleChunkSelected(): void87+public function testMarkStaleAndIsStaleChunkSelected(): void48 {88 {49-$selectionList = new SelectionList([], [], true);89+$selectionList = new SelectionList();50-$this->assertTrue($selectionList->isStaleChunkSelected());90+91+$this->assertFalse($selectionList->isStaleChunkSelected());92+93+$selectionList->markStale();519452-$selectionList2 = new SelectionList([], [], false);95+$this->assertTrue($selectionList->isStaleChunkSelected());53-$this->assertFalse($selectionList2->isStaleChunkSelected());54 }96 }559756public function testIsFullChunk(): void98public function testIsFullChunk(): void57 {99 {58-$chunkSize = 200;100+$selectionList = new SelectionList();59-101+$selectionList->setChunkSize(self::CHUNK_SIZE);60-$fullList = range(1, $chunkSize);102+61-$selectionList = new SelectionList(103+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, self::CHUNK_SIZE));62- priorityEntityIdList: $fullList,104+63- normalEntityIdList: [],105+$this->assertTrue($selectionList->isFullChunk());64- chunkSize: $chunkSize,106+ }65- );107+108+public function testIsNotFullChunkWhenBelowChunkSize(): void109+ {110+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);111+112+$selectionList = new SelectionList();113+$selectionList->setChunkSize(self::CHUNK_SIZE);114+115+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range(1, $halfRange));116+117+$this->assertFalse($selectionList->isFullChunk());118+ }119+120+public function testIsFullChunkAcrossMultiplePriorityGroups(): void121+ {122+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);123+124+$selectionList = new SelectionList();125+$selectionList->setChunkSize(self::CHUNK_SIZE);126+127+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, $halfRange));128+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range($halfRange + 1, self::CHUNK_SIZE));129+130+$this->assertTrue($selectionList->isFullChunk());131+ }132+133+public function testSetChunkSizeAffectsIsFullChunk(): void134+ {135+$selectionList = new SelectionList();136+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [1, 2, 3]);137+138+$selectionList->setChunkSize(3);66$this->assertTrue($selectionList->isFullChunk());139$this->assertTrue($selectionList->isFullChunk());6714068-$halfRange = (int) ceil($chunkSize / 2);141+$selectionList->setChunkSize(50);69-142+$this->assertFalse($selectionList->isFullChunk());70-$notFullList = range(1, $halfRange);71-$selectionList2 = new SelectionList(72- priorityEntityIdList: $notFullList,73- normalEntityIdList: [],74- chunkSize: $chunkSize,75- );76-$this->assertFalse($selectionList2->isFullChunk());77-78-$priorityRange = range(1, $halfRange);79-$normalRange = range($halfRange + 1, $chunkSize);80-81-$selectionList3 = new SelectionList(82- priorityEntityIdList: $priorityRange,83- normalEntityIdList: $normalRange,84- chunkSize: $chunkSize,85- );86-$this->assertTrue($selectionList3->isFullChunk());87 }143 }88}144}</selection>” selected. Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
You said
I’m on page “<tabTitle>JY-20808 low priority indexing queue by Vasil-Jimi</tabTitle>” with “<selection>@@ -5,84 +5,140 @@5namespace Tests\Unit\Component\ES\Processor\DTOs;5namespace Tests\Unit\Component\ES\Processor\DTOs;667use Jiminny\Component\ES\Processor\DTOs\SelectionList;7use Jiminny\Component\ES\Processor\DTOs\SelectionList;8+use Jiminny\Component\ES\QueuePriorityEnum;8use PHPUnit\Framework\Attributes\CoversClass;9use PHPUnit\Framework\Attributes\CoversClass;9use PHPUnit\Framework\TestCase;10use PHPUnit\Framework\TestCase;101111#[CoversClass(SelectionList::class)]12#[CoversClass(SelectionList::class)]12final class SelectionListTest extends TestCase13final class SelectionListTest extends TestCase13{14{14-public function testGetEntityIds(): void15+private const int CHUNK_SIZE = 100;16+17+public function testAddEntityListAndGetAllIds(): void18+ {19+$selectionList = new SelectionList();20+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);21+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);22+23+$this->assertSame([1, 2, 3, 4], $selectionList->getAllIds());24+ }25+26+public function testAddEntityListMergesMultipleCallsForSamePriority(): void27+ {28+$selectionList = new SelectionList();29+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);30+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [3, 4]);31+32+$this->assertSame([1, 2, 3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));33+ }34+35+public function testGetEntityListItemsByGroup(): void36+ {37+$selectionList = new SelectionList();38+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);39+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);40+$selectionList->addEntityList(QueuePriorityEnum::LOW, [5, 6]);41+42+$this->assertSame([1, 2], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));43+$this->assertSame([3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::NORMAL));44+$this->assertSame([5, 6], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::LOW));45+ }46+47+public function testGetEntityListItemsByGroupReturnsEmptyArrayForUnknownGroup(): void15 {48 {16-$priority = ['p1', 'p2'];49+$selectionList = new SelectionList();17-$normal = ['n1', 'n2'];50+18-$selectionList = new SelectionList($priority, $normal);51+$this->assertSame([], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));52+ }195320-$this->assertSame($priority, $selectionList->getHighPriorityEntityIds());54+public function testGetEntityListGroups(): void21-$this->assertSame($normal, $selectionList->getNormalPriorityEntityId());55+ {56+$selectionList = new SelectionList();57+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);58+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2]);225923-$this->assertSame(['p1', 'p2', 'n1', 'n2'], $selectionList->getAllIds());60+$this->assertSame(['high', 'normal'], $selectionList->getEntityListGroups());24 }61 }256226public function testCountReturnsTotalCount(): void63public function testCountReturnsTotalCount(): void27 {64 {28-$selectionList = new SelectionList(['p1'], ['n1', 'n2']);65+$selectionList = new SelectionList();66+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);67+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2, 3]);68+29$this->assertSame(3, $selectionList->count());69$this->assertSame(3, $selectionList->count());30 }70 }317132-public function testIsEmptyReturnsTrueWhenBothListsAreEmpty(): void72+public function testIsEmptyReturnsTrueWhenNoEntitiesAdded(): void33 {73 {34-$selectionList = new SelectionList([], []);74+$selectionList = new SelectionList();75+35$this->assertTrue($selectionList->isEmpty());76$this->assertTrue($selectionList->isEmpty());36 }77 }377838-public function testIsEmptyReturnsFalseWhenAnyListIsNotEmpty(): void79+public function testIsEmptyReturnsFalseWhenEntitiesAdded(): void39 {80 {40-$selectionList = new SelectionList(['p1'], []);81+$selectionList = new SelectionList();41-$this->assertFalse($selectionList->isEmpty());82+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);428343-$selectionList2 = new SelectionList([], ['n1']);84+$this->assertFalse($selectionList->isEmpty());44-$this->assertFalse($selectionList2->isEmpty());45 }85 }468647-public function testIsStaleChunkSelected(): void87+public function testMarkStaleAndIsStaleChunkSelected(): void48 {88 {49-$selectionList = new SelectionList([], [], true);89+$selectionList = new SelectionList();50-$this->assertTrue($selectionList->isStaleChunkSelected());90+91+$this->assertFalse($selectionList->isStaleChunkSelected());92+93+$selectionList->markStale();519452-$selectionList2 = new SelectionList([], [], false);95+$this->assertTrue($selectionList->isStaleChunkSelected());53-$this->assertFalse($selectionList2->isStaleChunkSelected());54 }96 }559756public function testIsFullChunk(): void98public function testIsFullChunk(): void57 {99 {58-$chunkSize = 200;100+$selectionList = new SelectionList();59-101+$selectionList->setChunkSize(self::CHUNK_SIZE);60-$fullList = range(1, $chunkSize);102+61-$selectionList = new SelectionList(103+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, self::CHUNK_SIZE));62- priorityEntityIdList: $fullList,104+63- normalEntityIdList: [],105+$this->assertTrue($selectionList->isFullChunk());64- chunkSize: $chunkSize,106+ }65- );107+108+public function testIsNotFullChunkWhenBelowChunkSize(): void109+ {110+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);111+112+$selectionList = new SelectionList();113+$selectionList->setChunkSize(self::CHUNK_SIZE);114+115+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range(1, $halfRange));116+117+$this->assertFalse($selectionList->isFullChunk());118+ }119+120+public function testIsFullChunkAcrossMultiplePriorityGroups(): void121+ {122+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);123+124+$selectionList = new SelectionList();125+$selectionList->setChunkSize(self::CHUNK_SIZE);126+127+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, $halfRange));128+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range($halfRange + 1, self::CHUNK_SIZE));129+130+$this->assertTrue($selectionList->isFullChunk());131+ }132+133+public function testSetChunkSizeAffectsIsFullChunk(): void134+ {135+$selectionList = new SelectionList();136+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [1, 2, 3]);137+138+$selectionList->setChunkSize(3);66$this->assertTrue($selectionList->isFullChunk());139$this->assertTrue($selectionList->isFullChunk());6714068-$halfRange = (int) ceil($chunkSize / 2);141+$selectionList->setChunkSize(50);69-142+$this->assertFalse($selectionList->isFullChunk());70-$notFullList = range(1, $halfRange);71-$selectionList2 = new SelectionList(72- priorityEntityIdList: $notFullList,73- normalEntityIdList: [],74- chunkSize: $chunkSize,75- );76-$this->assertFalse($selectionList2->isFullChunk());77-78-$priorityRange = range(1, $halfRange);79-$normalRange = range($halfRange + 1, $chunkSize);80-81-$selectionList3 = new SelectionList(82- priorityEntityIdList: $priorityRange,83- normalEntityIdList: $normalRange,84- chunkSize: $chunkSize,85- );86-$this->assertTrue($selectionList3->isFullChunk());87 }143 }88}144}</selection>” selected.
Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
Expand
Listen
Gemini said
Gemini said
Here is a precise and concise summary of the code selection, which refactors
SelectionListTest
to accommodate a shift from fixed high/normal priority properties to a more dynamic, enum-driven priority group architecture.
Refactored Priority Handling
Refactored Priority Handling
Dynamic Priority Groups:
Replaces fixed high/normal array parameters with the
QueuePriorityEnum
(
HIGH
,
NORMAL
,
LOW
), allowing entity lists to be managed dynamically by group types.
Merged Registrations:
Validates that multiple
addEntityList()
calls targeting the same priority level properly merge their data instead of overwriting it.
Group Querying:
Tests new methods
getEntityListItemsByGroup()
and
getEntityListGroups()
to retrieve group-specific IDs or an array of active group names (e.g.,
['high', 'normal']
).
Updated State and Count Validations
Updated State and Count Validations
Instantiation:
Tests now instantiate
SelectionList
without initial constructor arguments, using setters and action methods instead.
Empty States:
Updates assertions (
isEmpty()
) to verify state based on whether any entities have been dynamically added, rather than checking pre-defined constructor arrays.
Stale Flags:
Changes from passing a
stale
boolean via the constructor to explicitly triggering a mutable
$selectionList->markStale()
method.
Chunk Capacity Behavior
Chunk Capacity Behavior
Flexible Chunk Sizes:
Introduces a
setChunkSize()
method, replacing the constructor-configured chunk boundary.
Capacity Assertions:
Retains and updates the logic for
isFullChunk()
, ensuring it accurately evaluates capacity when elements span multiple dynamic priority groups or when the chunk limit is altered mid-lifecycle.
Good response
Bad response
Share & export
Copy
Show more options
Copy prompt
You said Are there any issues or potential bolltenecks
You said
Are there any issues or potential bolltenecks
Listen
Show thinking
Gemini said
Gemini said
Based on the test diff you provided, we can infer a few potential issues and architectural bottlenecks in the underlying
SelectionList
implementation. While the tests are well-structured, the behavior they describe hints at a few areas you might want to keep an eye on, particularly for an Elasticsearch (ES) processor queue.
Here are the potential issues and bottlenecks to consider:
1. Array Merging Overhead (Performance)
1. Array Merging Overhead (Performance)
The
testAddEntityListMergesMultipleCallsForSamePriority
test shows that calling
addEntityList()
multiple times for the same priority group merges the arrays.
The Bottleneck:
If the underlying implementation uses
array_merge()
inside a loop to append these IDs, it creates a new array in memory every time it's called. If you are processing thousands of entities and appending them in small batches, this can lead to memory bloat and CPU degradation due to constant array reallocation.
Mitigation:
Ensure the implementation handles batch appends efficiently (e.g., using the spread operator
[...$existing, ...$new]
or appending via references) or groups the arrays before doing a single merge.
2. Lack of Uniqueness/Deduplication (Logic)
2. Lack of Uniqueness/Deduplication (Logic)
None of the tests explicitly verify what happens if duplicate IDs are added. For example, if you call
addEntityList(QueuePriorityEnum::HIGH, [1, 2])
and then
addEntityList(QueuePriorityEnum::HIGH, [2, 3])
.
The Issue:
Does the getter return
[1, 2, 2, 3]
or...
|
[{"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":"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 I’m on page “<tabTitle>JY-20808 low priority indexing queue by Vasil-Jimi</tabTitle>” with “<selection>@@ -5,84 +5,140 @@5namespace Tests\\Unit\\Component\\ES\\Processor\\DTOs;5namespace Tests\\Unit\\Component\\ES\\Processor\\DTOs;667use Jiminny\\Component\\ES\\Processor\\DTOs\\SelectionList;7use Jiminny\\Component\\ES\\Processor\\DTOs\\SelectionList;8+use Jiminny\\Component\\ES\\QueuePriorityEnum;8use PHPUnit\\Framework\\Attributes\\CoversClass;9use PHPUnit\\Framework\\Attributes\\CoversClass;9use PHPUnit\\Framework\\TestCase;10use PHPUnit\\Framework\\TestCase;101111#[CoversClass(SelectionList::class)]12#[CoversClass(SelectionList::class)]12final class SelectionListTest extends TestCase13final class SelectionListTest extends TestCase13{14{14-public function testGetEntityIds(): void15+private const int CHUNK_SIZE = 100;16+17+public function testAddEntityListAndGetAllIds(): void18+ {19+$selectionList = new SelectionList();20+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);21+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);22+23+$this->assertSame([1, 2, 3, 4], $selectionList->getAllIds());24+ }25+26+public function testAddEntityListMergesMultipleCallsForSamePriority(): void27+ {28+$selectionList = new SelectionList();29+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);30+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [3, 4]);31+32+$this->assertSame([1, 2, 3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));33+ }34+35+public function testGetEntityListItemsByGroup(): void36+ {37+$selectionList = new SelectionList();38+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);39+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);40+$selectionList->addEntityList(QueuePriorityEnum::LOW, [5, 6]);41+42+$this->assertSame([1, 2], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));43+$this->assertSame([3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::NORMAL));44+$this->assertSame([5, 6], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::LOW));45+ }46+47+public function testGetEntityListItemsByGroupReturnsEmptyArrayForUnknownGroup(): void15 {48 {16-$priority = ['p1', 'p2'];49+$selectionList = new SelectionList();17-$normal = ['n1', 'n2'];50+18-$selectionList = new SelectionList($priority, $normal);51+$this->assertSame([], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));52+ }195320-$this->assertSame($priority, $selectionList->getHighPriorityEntityIds());54+public function testGetEntityListGroups(): void21-$this->assertSame($normal, $selectionList->getNormalPriorityEntityId());55+ {56+$selectionList = new SelectionList();57+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);58+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2]);225923-$this->assertSame(['p1', 'p2', 'n1', 'n2'], $selectionList->getAllIds());60+$this->assertSame(['high', 'normal'], $selectionList->getEntityListGroups());24 }61 }256226public function testCountReturnsTotalCount(): void63public function testCountReturnsTotalCount(): void27 {64 {28-$selectionList = new SelectionList(['p1'], ['n1', 'n2']);65+$selectionList = new SelectionList();66+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);67+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2, 3]);68+29$this->assertSame(3, $selectionList->count());69$this->assertSame(3, $selectionList->count());30 }70 }317132-public function testIsEmptyReturnsTrueWhenBothListsAreEmpty(): void72+public function testIsEmptyReturnsTrueWhenNoEntitiesAdded(): void33 {73 {34-$selectionList = new SelectionList([], []);74+$selectionList = new SelectionList();75+35$this->assertTrue($selectionList->isEmpty());76$this->assertTrue($selectionList->isEmpty());36 }77 }377838-public function testIsEmptyReturnsFalseWhenAnyListIsNotEmpty(): void79+public function testIsEmptyReturnsFalseWhenEntitiesAdded(): void39 {80 {40-$selectionList = new SelectionList(['p1'], []);81+$selectionList = new SelectionList();41-$this->assertFalse($selectionList->isEmpty());82+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);428343-$selectionList2 = new SelectionList([], ['n1']);84+$this->assertFalse($selectionList->isEmpty());44-$this->assertFalse($selectionList2->isEmpty());45 }85 }468647-public function testIsStaleChunkSelected(): void87+public function testMarkStaleAndIsStaleChunkSelected(): void48 {88 {49-$selectionList = new SelectionList([], [], true);89+$selectionList = new SelectionList();50-$this->assertTrue($selectionList->isStaleChunkSelected());90+91+$this->assertFalse($selectionList->isStaleChunkSelected());92+93+$selectionList->markStale();519452-$selectionList2 = new SelectionList([], [], false);95+$this->assertTrue($selectionList->isStaleChunkSelected());53-$this->assertFalse($selectionList2->isStaleChunkSelected());54 }96 }559756public function testIsFullChunk(): void98public function testIsFullChunk(): void57 {99 {58-$chunkSize = 200;100+$selectionList = new SelectionList();59-101+$selectionList->setChunkSize(self::CHUNK_SIZE);60-$fullList = range(1, $chunkSize);102+61-$selectionList = new SelectionList(103+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, self::CHUNK_SIZE));62- priorityEntityIdList: $fullList,104+63- normalEntityIdList: [],105+$this->assertTrue($selectionList->isFullChunk());64- chunkSize: $chunkSize,106+ }65- );107+108+public function testIsNotFullChunkWhenBelowChunkSize(): void109+ {110+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);111+112+$selectionList = new SelectionList();113+$selectionList->setChunkSize(self::CHUNK_SIZE);114+115+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range(1, $halfRange));116+117+$this->assertFalse($selectionList->isFullChunk());118+ }119+120+public function testIsFullChunkAcrossMultiplePriorityGroups(): void121+ {122+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);123+124+$selectionList = new SelectionList();125+$selectionList->setChunkSize(self::CHUNK_SIZE);126+127+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, $halfRange));128+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range($halfRange + 1, self::CHUNK_SIZE));129+130+$this->assertTrue($selectionList->isFullChunk());131+ }132+133+public function testSetChunkSizeAffectsIsFullChunk(): void134+ {135+$selectionList = new SelectionList();136+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [1, 2, 3]);137+138+$selectionList->setChunkSize(3);66$this->assertTrue($selectionList->isFullChunk());139$this->assertTrue($selectionList->isFullChunk());6714068-$halfRange = (int) ceil($chunkSize / 2);141+$selectionList->setChunkSize(50);69-142+$this->assertFalse($selectionList->isFullChunk());70-$notFullList = range(1, $halfRange);71-$selectionList2 = new SelectionList(72- priorityEntityIdList: $notFullList,73- normalEntityIdList: [],74- chunkSize: $chunkSize,75- );76-$this->assertFalse($selectionList2->isFullChunk());77-78-$priorityRange = range(1, $halfRange);79-$normalRange = range($halfRange + 1, $chunkSize);80-81-$selectionList3 = new SelectionList(82- priorityEntityIdList: $priorityRange,83- normalEntityIdList: $normalRange,84- chunkSize: $chunkSize,85- );86-$this->assertTrue($selectionList3->isFullChunk());87 }143 }88}144}</selection>” selected. Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.","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":"I’m on page “<tabTitle>JY-20808 low priority indexing queue by Vasil-Jimi</tabTitle>” with “<selection>@@ -5,84 +5,140 @@5namespace Tests\\Unit\\Component\\ES\\Processor\\DTOs;5namespace Tests\\Unit\\Component\\ES\\Processor\\DTOs;667use Jiminny\\Component\\ES\\Processor\\DTOs\\SelectionList;7use Jiminny\\Component\\ES\\Processor\\DTOs\\SelectionList;8+use Jiminny\\Component\\ES\\QueuePriorityEnum;8use PHPUnit\\Framework\\Attributes\\CoversClass;9use PHPUnit\\Framework\\Attributes\\CoversClass;9use PHPUnit\\Framework\\TestCase;10use PHPUnit\\Framework\\TestCase;101111#[CoversClass(SelectionList::class)]12#[CoversClass(SelectionList::class)]12final class SelectionListTest extends TestCase13final class SelectionListTest extends TestCase13{14{14-public function testGetEntityIds(): void15+private const int CHUNK_SIZE = 100;16+17+public function testAddEntityListAndGetAllIds(): void18+ {19+$selectionList = new SelectionList();20+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);21+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);22+23+$this->assertSame([1, 2, 3, 4], $selectionList->getAllIds());24+ }25+26+public function testAddEntityListMergesMultipleCallsForSamePriority(): void27+ {28+$selectionList = new SelectionList();29+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);30+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [3, 4]);31+32+$this->assertSame([1, 2, 3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));33+ }34+35+public function testGetEntityListItemsByGroup(): void36+ {37+$selectionList = new SelectionList();38+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);39+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);40+$selectionList->addEntityList(QueuePriorityEnum::LOW, [5, 6]);41+42+$this->assertSame([1, 2], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));43+$this->assertSame([3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::NORMAL));44+$this->assertSame([5, 6], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::LOW));45+ }46+47+public function testGetEntityListItemsByGroupReturnsEmptyArrayForUnknownGroup(): void15 {48 {16-$priority = ['p1', 'p2'];49+$selectionList = new SelectionList();17-$normal = ['n1', 'n2'];50+18-$selectionList = new SelectionList($priority, $normal);51+$this->assertSame([], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));52+ }195320-$this->assertSame($priority, $selectionList->getHighPriorityEntityIds());54+public function testGetEntityListGroups(): void21-$this->assertSame($normal, $selectionList->getNormalPriorityEntityId());55+ {56+$selectionList = new SelectionList();57+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);58+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2]);225923-$this->assertSame(['p1', 'p2', 'n1', 'n2'], $selectionList->getAllIds());60+$this->assertSame(['high', 'normal'], $selectionList->getEntityListGroups());24 }61 }256226public function testCountReturnsTotalCount(): void63public function testCountReturnsTotalCount(): void27 {64 {28-$selectionList = new SelectionList(['p1'], ['n1', 'n2']);65+$selectionList = new SelectionList();66+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);67+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2, 3]);68+29$this->assertSame(3, $selectionList->count());69$this->assertSame(3, $selectionList->count());30 }70 }317132-public function testIsEmptyReturnsTrueWhenBothListsAreEmpty(): void72+public function testIsEmptyReturnsTrueWhenNoEntitiesAdded(): void33 {73 {34-$selectionList = new SelectionList([], []);74+$selectionList = new SelectionList();75+35$this->assertTrue($selectionList->isEmpty());76$this->assertTrue($selectionList->isEmpty());36 }77 }377838-public function testIsEmptyReturnsFalseWhenAnyListIsNotEmpty(): void79+public function testIsEmptyReturnsFalseWhenEntitiesAdded(): void39 {80 {40-$selectionList = new SelectionList(['p1'], []);81+$selectionList = new SelectionList();41-$this->assertFalse($selectionList->isEmpty());82+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);428343-$selectionList2 = new SelectionList([], ['n1']);84+$this->assertFalse($selectionList->isEmpty());44-$this->assertFalse($selectionList2->isEmpty());45 }85 }468647-public function testIsStaleChunkSelected(): void87+public function testMarkStaleAndIsStaleChunkSelected(): void48 {88 {49-$selectionList = new SelectionList([], [], true);89+$selectionList = new SelectionList();50-$this->assertTrue($selectionList->isStaleChunkSelected());90+91+$this->assertFalse($selectionList->isStaleChunkSelected());92+93+$selectionList->markStale();519452-$selectionList2 = new SelectionList([], [], false);95+$this->assertTrue($selectionList->isStaleChunkSelected());53-$this->assertFalse($selectionList2->isStaleChunkSelected());54 }96 }559756public function testIsFullChunk(): void98public function testIsFullChunk(): void57 {99 {58-$chunkSize = 200;100+$selectionList = new SelectionList();59-101+$selectionList->setChunkSize(self::CHUNK_SIZE);60-$fullList = range(1, $chunkSize);102+61-$selectionList = new SelectionList(103+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, self::CHUNK_SIZE));62- priorityEntityIdList: $fullList,104+63- normalEntityIdList: [],105+$this->assertTrue($selectionList->isFullChunk());64- chunkSize: $chunkSize,106+ }65- );107+108+public function testIsNotFullChunkWhenBelowChunkSize(): void109+ {110+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);111+112+$selectionList = new SelectionList();113+$selectionList->setChunkSize(self::CHUNK_SIZE);114+115+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range(1, $halfRange));116+117+$this->assertFalse($selectionList->isFullChunk());118+ }119+120+public function testIsFullChunkAcrossMultiplePriorityGroups(): void121+ {122+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);123+124+$selectionList = new SelectionList();125+$selectionList->setChunkSize(self::CHUNK_SIZE);126+127+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, $halfRange));128+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range($halfRange + 1, self::CHUNK_SIZE));129+130+$this->assertTrue($selectionList->isFullChunk());131+ }132+133+public function testSetChunkSizeAffectsIsFullChunk(): void134+ {135+$selectionList = new SelectionList();136+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [1, 2, 3]);137+138+$selectionList->setChunkSize(3);66$this->assertTrue($selectionList->isFullChunk());139$this->assertTrue($selectionList->isFullChunk());6714068-$halfRange = (int) ceil($chunkSize / 2);141+$selectionList->setChunkSize(50);69-142+$this->assertFalse($selectionList->isFullChunk());70-$notFullList = range(1, $halfRange);71-$selectionList2 = new SelectionList(72- priorityEntityIdList: $notFullList,73- normalEntityIdList: [],74- chunkSize: $chunkSize,75- );76-$this->assertFalse($selectionList2->isFullChunk());77-78-$priorityRange = range(1, $halfRange);79-$normalRange = range($halfRange + 1, $chunkSize);80-81-$selectionList3 = new SelectionList(82- priorityEntityIdList: $priorityRange,83- normalEntityIdList: $normalRange,84- chunkSize: $chunkSize,85- );86-$this->assertTrue($selectionList3->isFullChunk());87 }143 }88}144}</selection>” selected.","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Expand","depth":21,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"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":"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":"Here is a precise and concise summary of the code selection, which refactors","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SelectionListTest","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"to accommodate a shift from fixed high/normal priority properties to a more dynamic, enum-driven priority group architecture.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Refactored Priority Handling","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Refactored Priority Handling","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Dynamic Priority Groups:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Replaces fixed high/normal array parameters with the","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"QueuePriorityEnum","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"HIGH","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"NORMAL","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"LOW","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"), allowing entity lists to be managed dynamically by group types.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Merged Registrations:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Validates that multiple","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"addEntityList()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"calls targeting the same priority level properly merge their data instead of overwriting it.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Group Querying:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Tests new methods","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"getEntityListItemsByGroup()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"and","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"getEntityListGroups()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"to retrieve group-specific IDs or an array of active group names (e.g.,","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"['high', 'normal']","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":").","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Updated State and Count Validations","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Updated State and Count Validations","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Instantiation:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Tests now instantiate","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SelectionList","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"without initial constructor arguments, using setters and action methods instead.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Empty States:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Updates assertions (","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"isEmpty()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":") to verify state based on whether any entities have been dynamically added, rather than checking pre-defined constructor arrays.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Stale Flags:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Changes from passing a","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"stale","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"boolean via the constructor to explicitly triggering a mutable","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$selectionList->markStale()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"method.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Chunk Capacity Behavior","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Chunk Capacity Behavior","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Flexible Chunk Sizes:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Introduces a","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"setChunkSize()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"method, replacing the constructor-configured chunk boundary.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Capacity Assertions:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Retains and updates the logic for","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"isFullChunk()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":", ensuring it accurately evaluates capacity when elements span multiple dynamic priority groups or when the chunk limit is altered mid-lifecycle.","depth":26,"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":"AXHeading","text":"You said Are there any issues or potential bolltenecks","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":"Are there any issues or potential bolltenecks","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":"Based on the test diff you provided, we can infer a few potential issues and architectural bottlenecks in the underlying","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SelectionList","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"implementation. While the tests are well-structured, the behavior they describe hints at a few areas you might want to keep an eye on, particularly for an Elasticsearch (ES) processor queue.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Here are the potential issues and bottlenecks to consider:","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"1. Array Merging Overhead (Performance)","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1. Array Merging Overhead (Performance)","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"testAddEntityListMergesMultipleCallsForSamePriority","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"test shows that calling","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"addEntityList()","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"multiple times for the same priority group merges the arrays.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The Bottleneck:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"If the underlying implementation uses","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"array_merge()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"inside a loop to append these IDs, it creates a new array in memory every time it's called. If you are processing thousands of entities and appending them in small batches, this can lead to memory bloat and CPU degradation due to constant array reallocation.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Mitigation:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Ensure the implementation handles batch appends efficiently (e.g., using the spread operator","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"[...$existing, ...$new]","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"or appending via references) or groups the arrays before doing a single merge.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"2. Lack of Uniqueness/Deduplication (Logic)","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2. Lack of Uniqueness/Deduplication (Logic)","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"None of the tests explicitly verify what happens if duplicate IDs are added. For example, if you call","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"addEntityList(QueuePriorityEnum::HIGH, [1, 2])","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"and then","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"addEntityList(QueuePriorityEnum::HIGH, [2, 3])","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":".","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The Issue:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Does the getter return","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"[1, 2, 2, 3]","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"or","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"}]...
|
-3080295626791821589
|
8165139447676957079
|
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
Copy prompt
You said I’m on page “<tabTitle>JY-20808 low priority indexing queue by Vasil-Jimi</tabTitle>” with “<selection>@@ -5,84 +5,140 @@5namespace Tests\Unit\Component\ES\Processor\DTOs;5namespace Tests\Unit\Component\ES\Processor\DTOs;667use Jiminny\Component\ES\Processor\DTOs\SelectionList;7use Jiminny\Component\ES\Processor\DTOs\SelectionList;8+use Jiminny\Component\ES\QueuePriorityEnum;8use PHPUnit\Framework\Attributes\CoversClass;9use PHPUnit\Framework\Attributes\CoversClass;9use PHPUnit\Framework\TestCase;10use PHPUnit\Framework\TestCase;101111#[CoversClass(SelectionList::class)]12#[CoversClass(SelectionList::class)]12final class SelectionListTest extends TestCase13final class SelectionListTest extends TestCase13{14{14-public function testGetEntityIds(): void15+private const int CHUNK_SIZE = 100;16+17+public function testAddEntityListAndGetAllIds(): void18+ {19+$selectionList = new SelectionList();20+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);21+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);22+23+$this->assertSame([1, 2, 3, 4], $selectionList->getAllIds());24+ }25+26+public function testAddEntityListMergesMultipleCallsForSamePriority(): void27+ {28+$selectionList = new SelectionList();29+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);30+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [3, 4]);31+32+$this->assertSame([1, 2, 3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));33+ }34+35+public function testGetEntityListItemsByGroup(): void36+ {37+$selectionList = new SelectionList();38+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);39+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);40+$selectionList->addEntityList(QueuePriorityEnum::LOW, [5, 6]);41+42+$this->assertSame([1, 2], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));43+$this->assertSame([3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::NORMAL));44+$this->assertSame([5, 6], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::LOW));45+ }46+47+public function testGetEntityListItemsByGroupReturnsEmptyArrayForUnknownGroup(): void15 {48 {16-$priority = ['p1', 'p2'];49+$selectionList = new SelectionList();17-$normal = ['n1', 'n2'];50+18-$selectionList = new SelectionList($priority, $normal);51+$this->assertSame([], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));52+ }195320-$this->assertSame($priority, $selectionList->getHighPriorityEntityIds());54+public function testGetEntityListGroups(): void21-$this->assertSame($normal, $selectionList->getNormalPriorityEntityId());55+ {56+$selectionList = new SelectionList();57+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);58+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2]);225923-$this->assertSame(['p1', 'p2', 'n1', 'n2'], $selectionList->getAllIds());60+$this->assertSame(['high', 'normal'], $selectionList->getEntityListGroups());24 }61 }256226public function testCountReturnsTotalCount(): void63public function testCountReturnsTotalCount(): void27 {64 {28-$selectionList = new SelectionList(['p1'], ['n1', 'n2']);65+$selectionList = new SelectionList();66+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);67+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2, 3]);68+29$this->assertSame(3, $selectionList->count());69$this->assertSame(3, $selectionList->count());30 }70 }317132-public function testIsEmptyReturnsTrueWhenBothListsAreEmpty(): void72+public function testIsEmptyReturnsTrueWhenNoEntitiesAdded(): void33 {73 {34-$selectionList = new SelectionList([], []);74+$selectionList = new SelectionList();75+35$this->assertTrue($selectionList->isEmpty());76$this->assertTrue($selectionList->isEmpty());36 }77 }377838-public function testIsEmptyReturnsFalseWhenAnyListIsNotEmpty(): void79+public function testIsEmptyReturnsFalseWhenEntitiesAdded(): void39 {80 {40-$selectionList = new SelectionList(['p1'], []);81+$selectionList = new SelectionList();41-$this->assertFalse($selectionList->isEmpty());82+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);428343-$selectionList2 = new SelectionList([], ['n1']);84+$this->assertFalse($selectionList->isEmpty());44-$this->assertFalse($selectionList2->isEmpty());45 }85 }468647-public function testIsStaleChunkSelected(): void87+public function testMarkStaleAndIsStaleChunkSelected(): void48 {88 {49-$selectionList = new SelectionList([], [], true);89+$selectionList = new SelectionList();50-$this->assertTrue($selectionList->isStaleChunkSelected());90+91+$this->assertFalse($selectionList->isStaleChunkSelected());92+93+$selectionList->markStale();519452-$selectionList2 = new SelectionList([], [], false);95+$this->assertTrue($selectionList->isStaleChunkSelected());53-$this->assertFalse($selectionList2->isStaleChunkSelected());54 }96 }559756public function testIsFullChunk(): void98public function testIsFullChunk(): void57 {99 {58-$chunkSize = 200;100+$selectionList = new SelectionList();59-101+$selectionList->setChunkSize(self::CHUNK_SIZE);60-$fullList = range(1, $chunkSize);102+61-$selectionList = new SelectionList(103+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, self::CHUNK_SIZE));62- priorityEntityIdList: $fullList,104+63- normalEntityIdList: [],105+$this->assertTrue($selectionList->isFullChunk());64- chunkSize: $chunkSize,106+ }65- );107+108+public function testIsNotFullChunkWhenBelowChunkSize(): void109+ {110+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);111+112+$selectionList = new SelectionList();113+$selectionList->setChunkSize(self::CHUNK_SIZE);114+115+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range(1, $halfRange));116+117+$this->assertFalse($selectionList->isFullChunk());118+ }119+120+public function testIsFullChunkAcrossMultiplePriorityGroups(): void121+ {122+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);123+124+$selectionList = new SelectionList();125+$selectionList->setChunkSize(self::CHUNK_SIZE);126+127+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, $halfRange));128+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range($halfRange + 1, self::CHUNK_SIZE));129+130+$this->assertTrue($selectionList->isFullChunk());131+ }132+133+public function testSetChunkSizeAffectsIsFullChunk(): void134+ {135+$selectionList = new SelectionList();136+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [1, 2, 3]);137+138+$selectionList->setChunkSize(3);66$this->assertTrue($selectionList->isFullChunk());139$this->assertTrue($selectionList->isFullChunk());6714068-$halfRange = (int) ceil($chunkSize / 2);141+$selectionList->setChunkSize(50);69-142+$this->assertFalse($selectionList->isFullChunk());70-$notFullList = range(1, $halfRange);71-$selectionList2 = new SelectionList(72- priorityEntityIdList: $notFullList,73- normalEntityIdList: [],74- chunkSize: $chunkSize,75- );76-$this->assertFalse($selectionList2->isFullChunk());77-78-$priorityRange = range(1, $halfRange);79-$normalRange = range($halfRange + 1, $chunkSize);80-81-$selectionList3 = new SelectionList(82- priorityEntityIdList: $priorityRange,83- normalEntityIdList: $normalRange,84- chunkSize: $chunkSize,85- );86-$this->assertTrue($selectionList3->isFullChunk());87 }143 }88}144}</selection>” selected. Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
You said
I’m on page “<tabTitle>JY-20808 low priority indexing queue by Vasil-Jimi</tabTitle>” with “<selection>@@ -5,84 +5,140 @@5namespace Tests\Unit\Component\ES\Processor\DTOs;5namespace Tests\Unit\Component\ES\Processor\DTOs;667use Jiminny\Component\ES\Processor\DTOs\SelectionList;7use Jiminny\Component\ES\Processor\DTOs\SelectionList;8+use Jiminny\Component\ES\QueuePriorityEnum;8use PHPUnit\Framework\Attributes\CoversClass;9use PHPUnit\Framework\Attributes\CoversClass;9use PHPUnit\Framework\TestCase;10use PHPUnit\Framework\TestCase;101111#[CoversClass(SelectionList::class)]12#[CoversClass(SelectionList::class)]12final class SelectionListTest extends TestCase13final class SelectionListTest extends TestCase13{14{14-public function testGetEntityIds(): void15+private const int CHUNK_SIZE = 100;16+17+public function testAddEntityListAndGetAllIds(): void18+ {19+$selectionList = new SelectionList();20+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);21+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);22+23+$this->assertSame([1, 2, 3, 4], $selectionList->getAllIds());24+ }25+26+public function testAddEntityListMergesMultipleCallsForSamePriority(): void27+ {28+$selectionList = new SelectionList();29+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);30+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [3, 4]);31+32+$this->assertSame([1, 2, 3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));33+ }34+35+public function testGetEntityListItemsByGroup(): void36+ {37+$selectionList = new SelectionList();38+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);39+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);40+$selectionList->addEntityList(QueuePriorityEnum::LOW, [5, 6]);41+42+$this->assertSame([1, 2], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));43+$this->assertSame([3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::NORMAL));44+$this->assertSame([5, 6], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::LOW));45+ }46+47+public function testGetEntityListItemsByGroupReturnsEmptyArrayForUnknownGroup(): void15 {48 {16-$priority = ['p1', 'p2'];49+$selectionList = new SelectionList();17-$normal = ['n1', 'n2'];50+18-$selectionList = new SelectionList($priority, $normal);51+$this->assertSame([], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));52+ }195320-$this->assertSame($priority, $selectionList->getHighPriorityEntityIds());54+public function testGetEntityListGroups(): void21-$this->assertSame($normal, $selectionList->getNormalPriorityEntityId());55+ {56+$selectionList = new SelectionList();57+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);58+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2]);225923-$this->assertSame(['p1', 'p2', 'n1', 'n2'], $selectionList->getAllIds());60+$this->assertSame(['high', 'normal'], $selectionList->getEntityListGroups());24 }61 }256226public function testCountReturnsTotalCount(): void63public function testCountReturnsTotalCount(): void27 {64 {28-$selectionList = new SelectionList(['p1'], ['n1', 'n2']);65+$selectionList = new SelectionList();66+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);67+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2, 3]);68+29$this->assertSame(3, $selectionList->count());69$this->assertSame(3, $selectionList->count());30 }70 }317132-public function testIsEmptyReturnsTrueWhenBothListsAreEmpty(): void72+public function testIsEmptyReturnsTrueWhenNoEntitiesAdded(): void33 {73 {34-$selectionList = new SelectionList([], []);74+$selectionList = new SelectionList();75+35$this->assertTrue($selectionList->isEmpty());76$this->assertTrue($selectionList->isEmpty());36 }77 }377838-public function testIsEmptyReturnsFalseWhenAnyListIsNotEmpty(): void79+public function testIsEmptyReturnsFalseWhenEntitiesAdded(): void39 {80 {40-$selectionList = new SelectionList(['p1'], []);81+$selectionList = new SelectionList();41-$this->assertFalse($selectionList->isEmpty());82+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);428343-$selectionList2 = new SelectionList([], ['n1']);84+$this->assertFalse($selectionList->isEmpty());44-$this->assertFalse($selectionList2->isEmpty());45 }85 }468647-public function testIsStaleChunkSelected(): void87+public function testMarkStaleAndIsStaleChunkSelected(): void48 {88 {49-$selectionList = new SelectionList([], [], true);89+$selectionList = new SelectionList();50-$this->assertTrue($selectionList->isStaleChunkSelected());90+91+$this->assertFalse($selectionList->isStaleChunkSelected());92+93+$selectionList->markStale();519452-$selectionList2 = new SelectionList([], [], false);95+$this->assertTrue($selectionList->isStaleChunkSelected());53-$this->assertFalse($selectionList2->isStaleChunkSelected());54 }96 }559756public function testIsFullChunk(): void98public function testIsFullChunk(): void57 {99 {58-$chunkSize = 200;100+$selectionList = new SelectionList();59-101+$selectionList->setChunkSize(self::CHUNK_SIZE);60-$fullList = range(1, $chunkSize);102+61-$selectionList = new SelectionList(103+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, self::CHUNK_SIZE));62- priorityEntityIdList: $fullList,104+63- normalEntityIdList: [],105+$this->assertTrue($selectionList->isFullChunk());64- chunkSize: $chunkSize,106+ }65- );107+108+public function testIsNotFullChunkWhenBelowChunkSize(): void109+ {110+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);111+112+$selectionList = new SelectionList();113+$selectionList->setChunkSize(self::CHUNK_SIZE);114+115+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range(1, $halfRange));116+117+$this->assertFalse($selectionList->isFullChunk());118+ }119+120+public function testIsFullChunkAcrossMultiplePriorityGroups(): void121+ {122+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);123+124+$selectionList = new SelectionList();125+$selectionList->setChunkSize(self::CHUNK_SIZE);126+127+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, $halfRange));128+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range($halfRange + 1, self::CHUNK_SIZE));129+130+$this->assertTrue($selectionList->isFullChunk());131+ }132+133+public function testSetChunkSizeAffectsIsFullChunk(): void134+ {135+$selectionList = new SelectionList();136+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [1, 2, 3]);137+138+$selectionList->setChunkSize(3);66$this->assertTrue($selectionList->isFullChunk());139$this->assertTrue($selectionList->isFullChunk());6714068-$halfRange = (int) ceil($chunkSize / 2);141+$selectionList->setChunkSize(50);69-142+$this->assertFalse($selectionList->isFullChunk());70-$notFullList = range(1, $halfRange);71-$selectionList2 = new SelectionList(72- priorityEntityIdList: $notFullList,73- normalEntityIdList: [],74- chunkSize: $chunkSize,75- );76-$this->assertFalse($selectionList2->isFullChunk());77-78-$priorityRange = range(1, $halfRange);79-$normalRange = range($halfRange + 1, $chunkSize);80-81-$selectionList3 = new SelectionList(82- priorityEntityIdList: $priorityRange,83- normalEntityIdList: $normalRange,84- chunkSize: $chunkSize,85- );86-$this->assertTrue($selectionList3->isFullChunk());87 }143 }88}144}</selection>” selected.
Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
Expand
Listen
Gemini said
Gemini said
Here is a precise and concise summary of the code selection, which refactors
SelectionListTest
to accommodate a shift from fixed high/normal priority properties to a more dynamic, enum-driven priority group architecture.
Refactored Priority Handling
Refactored Priority Handling
Dynamic Priority Groups:
Replaces fixed high/normal array parameters with the
QueuePriorityEnum
(
HIGH
,
NORMAL
,
LOW
), allowing entity lists to be managed dynamically by group types.
Merged Registrations:
Validates that multiple
addEntityList()
calls targeting the same priority level properly merge their data instead of overwriting it.
Group Querying:
Tests new methods
getEntityListItemsByGroup()
and
getEntityListGroups()
to retrieve group-specific IDs or an array of active group names (e.g.,
['high', 'normal']
).
Updated State and Count Validations
Updated State and Count Validations
Instantiation:
Tests now instantiate
SelectionList
without initial constructor arguments, using setters and action methods instead.
Empty States:
Updates assertions (
isEmpty()
) to verify state based on whether any entities have been dynamically added, rather than checking pre-defined constructor arrays.
Stale Flags:
Changes from passing a
stale
boolean via the constructor to explicitly triggering a mutable
$selectionList->markStale()
method.
Chunk Capacity Behavior
Chunk Capacity Behavior
Flexible Chunk Sizes:
Introduces a
setChunkSize()
method, replacing the constructor-configured chunk boundary.
Capacity Assertions:
Retains and updates the logic for
isFullChunk()
, ensuring it accurately evaluates capacity when elements span multiple dynamic priority groups or when the chunk limit is altered mid-lifecycle.
Good response
Bad response
Share & export
Copy
Show more options
Copy prompt
You said Are there any issues or potential bolltenecks
You said
Are there any issues or potential bolltenecks
Listen
Show thinking
Gemini said
Gemini said
Based on the test diff you provided, we can infer a few potential issues and architectural bottlenecks in the underlying
SelectionList
implementation. While the tests are well-structured, the behavior they describe hints at a few areas you might want to keep an eye on, particularly for an Elasticsearch (ES) processor queue.
Here are the potential issues and bottlenecks to consider:
1. Array Merging Overhead (Performance)
1. Array Merging Overhead (Performance)
The
testAddEntityListMergesMultipleCallsForSamePriority
test shows that calling
addEntityList()
multiple times for the same priority group merges the arrays.
The Bottleneck:
If the underlying implementation uses
array_merge()
inside a loop to append these IDs, it creates a new array in memory every time it's called. If you are processing thousands of entities and appending them in small batches, this can lead to memory bloat and CPU degradation due to constant array reallocation.
Mitigation:
Ensure the implementation handles batch appends efficiently (e.g., using the spread operator
[...$existing, ...$new]
or appending via references) or groups the arrays before doing a single merge.
2. Lack of Uniqueness/Deduplication (Logic)
2. Lack of Uniqueness/Deduplication (Logic)
None of the tests explicitly verify what happens if duplicate IDs are added. For example, if you call
addEntityList(QueuePriorityEnum::HIGH, [1, 2])
and then
addEntityList(QueuePriorityEnum::HIGH, [2, 3])
.
The Issue:
Does the getter return
[1, 2, 2, 3]
or...
|
55658
|
NULL
|
NULL
|
NULL
|
|
55661
|
1932
|
0
|
2026-05-19T06:36:43.175421+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779172603175_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
Copy prompt
You said I’m on page “<tabTitle>JY-20808 low priority indexing queue by Vasil-Jimi</tabTitle>” with “<selection>@@ -5,84 +5,140 @@5namespace Tests\Unit\Component\ES\Processor\DTOs;5namespace Tests\Unit\Component\ES\Processor\DTOs;667use Jiminny\Component\ES\Processor\DTOs\SelectionList;7use Jiminny\Component\ES\Processor\DTOs\SelectionList;8+use Jiminny\Component\ES\QueuePriorityEnum;8use PHPUnit\Framework\Attributes\CoversClass;9use PHPUnit\Framework\Attributes\CoversClass;9use PHPUnit\Framework\TestCase;10use PHPUnit\Framework\TestCase;101111#[CoversClass(SelectionList::class)]12#[CoversClass(SelectionList::class)]12final class SelectionListTest extends TestCase13final class SelectionListTest extends TestCase13{14{14-public function testGetEntityIds(): void15+private const int CHUNK_SIZE = 100;16+17+public function testAddEntityListAndGetAllIds(): void18+ {19+$selectionList = new SelectionList();20+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);21+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);22+23+$this->assertSame([1, 2, 3, 4], $selectionList->getAllIds());24+ }25+26+public function testAddEntityListMergesMultipleCallsForSamePriority(): void27+ {28+$selectionList = new SelectionList();29+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);30+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [3, 4]);31+32+$this->assertSame([1, 2, 3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));33+ }34+35+public function testGetEntityListItemsByGroup(): void36+ {37+$selectionList = new SelectionList();38+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);39+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);40+$selectionList->addEntityList(QueuePriorityEnum::LOW, [5, 6]);41+42+$this->assertSame([1, 2], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));43+$this->assertSame([3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::NORMAL));44+$this->assertSame([5, 6], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::LOW));45+ }46+47+public function testGetEntityListItemsByGroupReturnsEmptyArrayForUnknownGroup(): void15 {48 {16-$priority = ['p1', 'p2'];49+$selectionList = new SelectionList();17-$normal = ['n1', 'n2'];50+18-$selectionList = new SelectionList($priority, $normal);51+$this->assertSame([], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));52+ }195320-$this->assertSame($priority, $selectionList->getHighPriorityEntityIds());54+public function testGetEntityListGroups(): void21-$this->assertSame($normal, $selectionList->getNormalPriorityEntityId());55+ {56+$selectionList = new SelectionList();57+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);58+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2]);225923-$this->assertSame(['p1', 'p2', 'n1', 'n2'], $selectionList->getAllIds());60+$this->assertSame(['high', 'normal'], $selectionList->getEntityListGroups());24 }61 }256226public function testCountReturnsTotalCount(): void63public function testCountReturnsTotalCount(): void27 {64 {28-$selectionList = new SelectionList(['p1'], ['n1', 'n2']);65+$selectionList = new SelectionList();66+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);67+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2, 3]);68+29$this->assertSame(3, $selectionList->count());69$this->assertSame(3, $selectionList->count());30 }70 }317132-public function testIsEmptyReturnsTrueWhenBothListsAreEmpty(): void72+public function testIsEmptyReturnsTrueWhenNoEntitiesAdded(): void33 {73 {34-$selectionList = new SelectionList([], []);74+$selectionList = new SelectionList();75+35$this->assertTrue($selectionList->isEmpty());76$this->assertTrue($selectionList->isEmpty());36 }77 }377838-public function testIsEmptyReturnsFalseWhenAnyListIsNotEmpty(): void79+public function testIsEmptyReturnsFalseWhenEntitiesAdded(): void39 {80 {40-$selectionList = new SelectionList(['p1'], []);81+$selectionList = new SelectionList();41-$this->assertFalse($selectionList->isEmpty());82+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);428343-$selectionList2 = new SelectionList([], ['n1']);84+$this->assertFalse($selectionList->isEmpty());44-$this->assertFalse($selectionList2->isEmpty());45 }85 }468647-public function testIsStaleChunkSelected(): void87+public function testMarkStaleAndIsStaleChunkSelected(): void48 {88 {49-$selectionList = new SelectionList([], [], true);89+$selectionList = new SelectionList();50-$this->assertTrue($selectionList->isStaleChunkSelected());90+91+$this->assertFalse($selectionList->isStaleChunkSelected());92+93+$selectionList->markStale();519452-$selectionList2 = new SelectionList([], [], false);95+$this->assertTrue($selectionList->isStaleChunkSelected());53-$this->assertFalse($selectionList2->isStaleChunkSelected());54 }96 }559756public function testIsFullChunk(): void98public function testIsFullChunk(): void57 {99 {58-$chunkSize = 200;100+$selectionList = new SelectionList();59-101+$selectionList->setChunkSize(self::CHUNK_SIZE);60-$fullList = range(1, $chunkSize);102+61-$selectionList = new SelectionList(103+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, self::CHUNK_SIZE));62- priorityEntityIdList: $fullList,104+63- normalEntityIdList: [],105+$this->assertTrue($selectionList->isFullChunk());64- chunkSize: $chunkSize,106+ }65- );107+108+public function testIsNotFullChunkWhenBelowChunkSize(): void109+ {110+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);111+112+$selectionList = new SelectionList();113+$selectionList->setChunkSize(self::CHUNK_SIZE);114+115+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range(1, $halfRange));116+117+$this->assertFalse($selectionList->isFullChunk());118+ }119+120+public function testIsFullChunkAcrossMultiplePriorityGroups(): void121+ {122+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);123+124+$selectionList = new SelectionList();125+$selectionList->setChunkSize(self::CHUNK_SIZE);126+127+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, $halfRange));128+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range($halfRange + 1, self::CHUNK_SIZE));129+130+$this->assertTrue($selectionList->isFullChunk());131+ }132+133+public function testSetChunkSizeAffectsIsFullChunk(): void134+ {135+$selectionList = new SelectionList();136+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [1, 2, 3]);137+138+$selectionList->setChunkSize(3);66$this->assertTrue($selectionList->isFullChunk());139$this->assertTrue($selectionList->isFullChunk());6714068-$halfRange = (int) ceil($chunkSize / 2);141+$selectionList->setChunkSize(50);69-142+$this->assertFalse($selectionList->isFullChunk());70-$notFullList = range(1, $halfRange);71-$selectionList2 = new SelectionList(72- priorityEntityIdList: $notFullList,73- normalEntityIdList: [],74- chunkSize: $chunkSize,75- );76-$this->assertFalse($selectionList2->isFullChunk());77-78-$priorityRange = range(1, $halfRange);79-$normalRange = range($halfRange + 1, $chunkSize);80-81-$selectionList3 = new SelectionList(82- priorityEntityIdList: $priorityRange,83- normalEntityIdList: $normalRange,84- chunkSize: $chunkSize,85- );86-$this->assertTrue($selectionList3->isFullChunk());87 }143 }88}144}</selection>” selected. Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
You said
I’m on page “<tabTitle>JY-20808 low priority indexing queue by Vasil-Jimi</tabTitle>” with “<selection>@@ -5,84 +5,140 @@5namespace Tests\Unit\Component\ES\Processor\DTOs;5namespace Tests\Unit\Component\ES\Processor\DTOs;667use Jiminny\Component\ES\Processor\DTOs\SelectionList;7use Jiminny\Component\ES\Processor\DTOs\SelectionList;8+use Jiminny\Component\ES\QueuePriorityEnum;8use PHPUnit\Framework\Attributes\CoversClass;9use PHPUnit\Framework\Attributes\CoversClass;9use PHPUnit\Framework\TestCase;10use PHPUnit\Framework\TestCase;101111#[CoversClass(SelectionList::class)]12#[CoversClass(SelectionList::class)]12final class SelectionListTest extends TestCase13final class SelectionListTest extends TestCase13{14{14-public function testGetEntityIds(): void15+private const int CHUNK_SIZE = 100;16+17+public function testAddEntityListAndGetAllIds(): void18+ {19+$selectionList = new SelectionList();20+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);21+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);22+23+$this->assertSame([1, 2, 3, 4], $selectionList->getAllIds());24+ }25+26+public function testAddEntityListMergesMultipleCallsForSamePriority(): void27+ {28+$selectionList = new SelectionList();29+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);30+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [3, 4]);31+32+$this->assertSame([1, 2, 3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));33+ }34+35+public function testGetEntityListItemsByGroup(): void36+ {37+$selectionList = new SelectionList();38+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);39+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);40+$selectionList->addEntityList(QueuePriorityEnum::LOW, [5, 6]);41+42+$this->assertSame([1, 2], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));43+$this->assertSame([3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::NORMAL));44+$this->assertSame([5, 6], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::LOW));45+ }46+47+public function testGetEntityListItemsByGroupReturnsEmptyArrayForUnknownGroup(): void15 {48 {16-$priority = ['p1', 'p2'];49+$selectionList = new SelectionList();17-$normal = ['n1', 'n2'];50+18-$selectionList = new SelectionList($priority, $normal);51+$this->assertSame([], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));52+ }195320-$this->assertSame($priority, $selectionList->getHighPriorityEntityIds());54+public function testGetEntityListGroups(): void21-$this->assertSame($normal, $selectionList->getNormalPriorityEntityId());55+ {56+$selectionList = new SelectionList();57+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);58+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2]);225923-$this->assertSame(['p1', 'p2', 'n1', 'n2'], $selectionList->getAllIds());60+$this->assertSame(['high', 'normal'], $selectionList->getEntityListGroups());24 }61 }256226public function testCountReturnsTotalCount(): void63public function testCountReturnsTotalCount(): void27 {64 {28-$selectionList = new SelectionList(['p1'], ['n1', 'n2']);65+$selectionList = new SelectionList();66+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);67+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2, 3]);68+29$this->assertSame(3, $selectionList->count());69$this->assertSame(3, $selectionList->count());30 }70 }317132-public function testIsEmptyReturnsTrueWhenBothListsAreEmpty(): void72+public function testIsEmptyReturnsTrueWhenNoEntitiesAdded(): void33 {73 {34-$selectionList = new SelectionList([], []);74+$selectionList = new SelectionList();75+35$this->assertTrue($selectionList->isEmpty());76$this->assertTrue($selectionList->isEmpty());36 }77 }377838-public function testIsEmptyReturnsFalseWhenAnyListIsNotEmpty(): void79+public function testIsEmptyReturnsFalseWhenEntitiesAdded(): void39 {80 {40-$selectionList = new SelectionList(['p1'], []);81+$selectionList = new SelectionList();41-$this->assertFalse($selectionList->isEmpty());82+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);428343-$selectionList2 = new SelectionList([], ['n1']);84+$this->assertFalse($selectionList->isEmpty());44-$this->assertFalse($selectionList2->isEmpty());45 }85 }468647-public function testIsStaleChunkSelected(): void87+public function testMarkStaleAndIsStaleChunkSelected(): void48 {88 {49-$selectionList = new SelectionList([], [], true);89+$selectionList = new SelectionList();50-$this->assertTrue($selectionList->isStaleChunkSelected());90+91+$this->assertFalse($selectionList->isStaleChunkSelected());92+93+$selectionList->markStale();519452-$selectionList2 = new SelectionList([], [], false);95+$this->assertTrue($selectionList->isStaleChunkSelected());53-$this->assertFalse($selectionList2->isStaleChunkSelected());54 }96 }559756public function testIsFullChunk(): void98public function testIsFullChunk(): void57 {99 {58-$chunkSize = 200;100+$selectionList = new SelectionList();59-101+$selectionList->setChunkSize(self::CHUNK_SIZE);60-$fullList = range(1, $chunkSize);102+61-$selectionList = new SelectionList(103+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, self::CHUNK_SIZE));62- priorityEntityIdList: $fullList,104+63- normalEntityIdList: [],105+$this->assertTrue($selectionList->isFullChunk());64- chunkSize: $chunkSize,106+ }65- );107+108+public function testIsNotFullChunkWhenBelowChunkSize(): void109+ {110+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);111+112+$selectionList = new SelectionList();113+$selectionList->setChunkSize(self::CHUNK_SIZE);114+115+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range(1, $halfRange));116+117+$this->assertFalse($selectionList->isFullChunk());118+ }119+120+public function testIsFullChunkAcrossMultiplePriorityGroups(): void121+ {122+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);123+124+$selectionList = new SelectionList();125+$selectionList->setChunkSize(self::CHUNK_SIZE);126+127+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, $halfRange));128+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range($halfRange + 1, self::CHUNK_SIZE));129+130+$this->assertTrue($selectionList->isFullChunk());131+ }132+133+public function testSetChunkSizeAffectsIsFullChunk(): void134+ {135+$selectionList = new SelectionList();136+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [1, 2, 3]);137+138+$selectionList->setChunkSize(3);66$this->assertTrue($selectionList->isFullChunk());139$this->assertTrue($selectionList->isFullChunk());6714068-$halfRange = (int) ceil($chunkSize / 2);141+$selectionList->setChunkSize(50);69-142+$this->assertFalse($selectionList->isFullChunk());70-$notFullList = range(1, $halfRange);71-$selectionList2 = new SelectionList(72- priorityEntityIdList: $notFullList,73- normalEntityIdList: [],74- chunkSize: $chunkSize,75- );76-$this->assertFalse($selectionList2->isFullChunk());77-78-$priorityRange = range(1, $halfRange);79-$normalRange = range($halfRange + 1, $chunkSize);80-81-$selectionList3 = new SelectionList(82- priorityEntityIdList: $priorityRange,83- normalEntityIdList: $normalRange,84- chunkSize: $chunkSize,85- );86-$this->assertTrue($selectionList3->isFullChunk());87 }143 }88}144}</selection>” selected.
Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
Expand
Listen
Gemini said
Gemini said
Here is a precise and concise summary of the code selection, which refactors
SelectionListTest
to accommodate a shift from fixed high/normal priority properties to a more dynamic, enum-driven priority group architecture.
Refactored Priority Handling
Refactored Priority Handling
Dynamic Priority Groups:
Replaces fixed high/normal array parameters with the
QueuePriorityEnum
(
HIGH
,
NORMAL
,
LOW
), allowing entity lists to be managed dynamically by group types.
Merged Registrations:
Validates that multiple
addEntityList()
calls targeting the same priority level properly merge their data instead of overwriting it.
Group Querying:
Tests new methods
getEntityListItemsByGroup()
and
getEntityListGroups()
to retrieve group-specific IDs or an array of active group names (e.g.,
['high', 'normal']
).
Updated State and Count Validations
Updated State and Count Validations
Instantiation:
Tests now instantiate
SelectionList
without initial constructor arguments, using setters and action methods instead.
Empty States:
Updates assertions (
isEmpty()
) to verify state based on whether any entities have been dynamically added, rather than checking pre-defined constructor arrays.
Stale Flags:
Changes from passing a
stale
boolean via the constructor to explicitly triggering a mutable
$selectionList->markStale()
method.
Chunk Capacity Behavior
Chunk Capacity Behavior
Flexible Chunk Sizes:
Introduces a
setChunkSize()
method, replacing the constructor-configured chunk boundary.
Capacity Assertions:
Retains and updates the logic for
isFullChunk()
, ensuring it accurately evaluates capacity when elements span multiple dynamic priority groups or when the chunk limit is altered mid-lifecycle.
Good response
Bad response
Share & export
Copy
Show more options
Copy prompt
You said Are there any issues or potential bolltenecks
You said
Are there any issues or potential bolltenecks
Listen
Show thinking
Gemini said
Gemini said
Based on the test diff you provided, we can infer a few potential issues and architectural bottlenecks in the underlying
SelectionList
implementation. While the tests are well-structured, the behavior they describe hints at a few areas you might want to keep an eye on, particularly for an Elasticsearch (ES) processor queue.
Here are the potential issues and bottlenecks to consider:
1. Array Merging Overhead (Performance)
1. Array Merging Overhead (Performance)
The
testAddEntityListMergesMultipleCallsForSamePriority
test shows that calling
addEntityList()
multiple times for the same priority group merges the arrays.
The Bottleneck:
If the underlying implementation uses
array_merge()
inside a loop to append these IDs, it creates a new array in memory every time it's called. If you are processing thousands of entities and appending them in small batches, this can lead to memory bloat and CPU degradation due to constant array reallocation.
Mitigation:
Ensure the implementation handles batch appends efficiently (e.g., using the spread operator
[...$existing, ...$new]
or appending via references) or groups the arrays before doing a single merge.
2. Lack of Uniqueness/Deduplication (Logic)
2. Lack of Uniqueness/Deduplication (Logic)
None of the tests explicitly verify what happens if duplicate IDs are added. For example, if you call
addEntityList(QueuePriorityEnum::HIGH, [1, 2])
and then
addEntityList(QueuePriorityEnum::HIGH, [2, 3])
.
The Issue:
Does the getter return
[1, 2, 2, 3]
or
[1, 2, 3]
? If duplicates are not filtered out, your ES processor might end up indexing the same entity multiple times in a single chunk, which wastes I/O and processor cycles.
Mitigation:
The underlying class should ideally enforce uniqueness (e.g., using
array_unique()
before resolving the chunk, or using ID keys as associative array keys to naturally prevent duplicates).
3. Memory Consumption with Large Chunks (Scalability)
3. Memory Consumption with Large Chunks (Scalability)
The tests introduce
setChunkSize()
. If this chunk size is configured to be very large (e.g., tens of thousands of IDs to bulk-send to Elasticsearch).
The Bottleneck:
Holding massive arrays of IDs in memory across different priority groups can quickly hit PHP memory limits, especially if this
SelectionList
object is kept alive during a long-running daemon or cron job.
Mitigation:
Monitor memory usage if
CHUNK_SIZE
grows, and ensure the
SelectionList
object is properly destroyed (or garbage collected) after the chunk is processed to free up memory.
4. Type Juggling
4. Type Juggling
In the original code, string IDs were used (
['p1', 'p2']
). In the refactored tests, integer IDs are used (
[1, 2]
).
The Issue:
If your system handles UUIDs (strings) vs. relational DB auto-increments (integers), make sure the underlying implementation uses strict comparisons (
===
) where necessary, especially if deduplicating arrays, to prevent PHP from juggling
'1'
and
1
improperly.
Would you like me to draft a quick test case to check how the class currently handles duplicate IDs, or is deduplication intentionally handled further down your pipeline?
Good response
Bad response
Share & export
Copy
Show more options...
|
[{"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":"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 I’m on page “<tabTitle>JY-20808 low priority indexing queue by Vasil-Jimi</tabTitle>” with “<selection>@@ -5,84 +5,140 @@5namespace Tests\\Unit\\Component\\ES\\Processor\\DTOs;5namespace Tests\\Unit\\Component\\ES\\Processor\\DTOs;667use Jiminny\\Component\\ES\\Processor\\DTOs\\SelectionList;7use Jiminny\\Component\\ES\\Processor\\DTOs\\SelectionList;8+use Jiminny\\Component\\ES\\QueuePriorityEnum;8use PHPUnit\\Framework\\Attributes\\CoversClass;9use PHPUnit\\Framework\\Attributes\\CoversClass;9use PHPUnit\\Framework\\TestCase;10use PHPUnit\\Framework\\TestCase;101111#[CoversClass(SelectionList::class)]12#[CoversClass(SelectionList::class)]12final class SelectionListTest extends TestCase13final class SelectionListTest extends TestCase13{14{14-public function testGetEntityIds(): void15+private const int CHUNK_SIZE = 100;16+17+public function testAddEntityListAndGetAllIds(): void18+ {19+$selectionList = new SelectionList();20+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);21+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);22+23+$this->assertSame([1, 2, 3, 4], $selectionList->getAllIds());24+ }25+26+public function testAddEntityListMergesMultipleCallsForSamePriority(): void27+ {28+$selectionList = new SelectionList();29+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);30+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [3, 4]);31+32+$this->assertSame([1, 2, 3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));33+ }34+35+public function testGetEntityListItemsByGroup(): void36+ {37+$selectionList = new SelectionList();38+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);39+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);40+$selectionList->addEntityList(QueuePriorityEnum::LOW, [5, 6]);41+42+$this->assertSame([1, 2], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));43+$this->assertSame([3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::NORMAL));44+$this->assertSame([5, 6], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::LOW));45+ }46+47+public function testGetEntityListItemsByGroupReturnsEmptyArrayForUnknownGroup(): void15 {48 {16-$priority = ['p1', 'p2'];49+$selectionList = new SelectionList();17-$normal = ['n1', 'n2'];50+18-$selectionList = new SelectionList($priority, $normal);51+$this->assertSame([], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));52+ }195320-$this->assertSame($priority, $selectionList->getHighPriorityEntityIds());54+public function testGetEntityListGroups(): void21-$this->assertSame($normal, $selectionList->getNormalPriorityEntityId());55+ {56+$selectionList = new SelectionList();57+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);58+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2]);225923-$this->assertSame(['p1', 'p2', 'n1', 'n2'], $selectionList->getAllIds());60+$this->assertSame(['high', 'normal'], $selectionList->getEntityListGroups());24 }61 }256226public function testCountReturnsTotalCount(): void63public function testCountReturnsTotalCount(): void27 {64 {28-$selectionList = new SelectionList(['p1'], ['n1', 'n2']);65+$selectionList = new SelectionList();66+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);67+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2, 3]);68+29$this->assertSame(3, $selectionList->count());69$this->assertSame(3, $selectionList->count());30 }70 }317132-public function testIsEmptyReturnsTrueWhenBothListsAreEmpty(): void72+public function testIsEmptyReturnsTrueWhenNoEntitiesAdded(): void33 {73 {34-$selectionList = new SelectionList([], []);74+$selectionList = new SelectionList();75+35$this->assertTrue($selectionList->isEmpty());76$this->assertTrue($selectionList->isEmpty());36 }77 }377838-public function testIsEmptyReturnsFalseWhenAnyListIsNotEmpty(): void79+public function testIsEmptyReturnsFalseWhenEntitiesAdded(): void39 {80 {40-$selectionList = new SelectionList(['p1'], []);81+$selectionList = new SelectionList();41-$this->assertFalse($selectionList->isEmpty());82+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);428343-$selectionList2 = new SelectionList([], ['n1']);84+$this->assertFalse($selectionList->isEmpty());44-$this->assertFalse($selectionList2->isEmpty());45 }85 }468647-public function testIsStaleChunkSelected(): void87+public function testMarkStaleAndIsStaleChunkSelected(): void48 {88 {49-$selectionList = new SelectionList([], [], true);89+$selectionList = new SelectionList();50-$this->assertTrue($selectionList->isStaleChunkSelected());90+91+$this->assertFalse($selectionList->isStaleChunkSelected());92+93+$selectionList->markStale();519452-$selectionList2 = new SelectionList([], [], false);95+$this->assertTrue($selectionList->isStaleChunkSelected());53-$this->assertFalse($selectionList2->isStaleChunkSelected());54 }96 }559756public function testIsFullChunk(): void98public function testIsFullChunk(): void57 {99 {58-$chunkSize = 200;100+$selectionList = new SelectionList();59-101+$selectionList->setChunkSize(self::CHUNK_SIZE);60-$fullList = range(1, $chunkSize);102+61-$selectionList = new SelectionList(103+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, self::CHUNK_SIZE));62- priorityEntityIdList: $fullList,104+63- normalEntityIdList: [],105+$this->assertTrue($selectionList->isFullChunk());64- chunkSize: $chunkSize,106+ }65- );107+108+public function testIsNotFullChunkWhenBelowChunkSize(): void109+ {110+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);111+112+$selectionList = new SelectionList();113+$selectionList->setChunkSize(self::CHUNK_SIZE);114+115+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range(1, $halfRange));116+117+$this->assertFalse($selectionList->isFullChunk());118+ }119+120+public function testIsFullChunkAcrossMultiplePriorityGroups(): void121+ {122+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);123+124+$selectionList = new SelectionList();125+$selectionList->setChunkSize(self::CHUNK_SIZE);126+127+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, $halfRange));128+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range($halfRange + 1, self::CHUNK_SIZE));129+130+$this->assertTrue($selectionList->isFullChunk());131+ }132+133+public function testSetChunkSizeAffectsIsFullChunk(): void134+ {135+$selectionList = new SelectionList();136+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [1, 2, 3]);137+138+$selectionList->setChunkSize(3);66$this->assertTrue($selectionList->isFullChunk());139$this->assertTrue($selectionList->isFullChunk());6714068-$halfRange = (int) ceil($chunkSize / 2);141+$selectionList->setChunkSize(50);69-142+$this->assertFalse($selectionList->isFullChunk());70-$notFullList = range(1, $halfRange);71-$selectionList2 = new SelectionList(72- priorityEntityIdList: $notFullList,73- normalEntityIdList: [],74- chunkSize: $chunkSize,75- );76-$this->assertFalse($selectionList2->isFullChunk());77-78-$priorityRange = range(1, $halfRange);79-$normalRange = range($halfRange + 1, $chunkSize);80-81-$selectionList3 = new SelectionList(82- priorityEntityIdList: $priorityRange,83- normalEntityIdList: $normalRange,84- chunkSize: $chunkSize,85- );86-$this->assertTrue($selectionList3->isFullChunk());87 }143 }88}144}</selection>” selected. Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.","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":"I’m on page “<tabTitle>JY-20808 low priority indexing queue by Vasil-Jimi</tabTitle>” with “<selection>@@ -5,84 +5,140 @@5namespace Tests\\Unit\\Component\\ES\\Processor\\DTOs;5namespace Tests\\Unit\\Component\\ES\\Processor\\DTOs;667use Jiminny\\Component\\ES\\Processor\\DTOs\\SelectionList;7use Jiminny\\Component\\ES\\Processor\\DTOs\\SelectionList;8+use Jiminny\\Component\\ES\\QueuePriorityEnum;8use PHPUnit\\Framework\\Attributes\\CoversClass;9use PHPUnit\\Framework\\Attributes\\CoversClass;9use PHPUnit\\Framework\\TestCase;10use PHPUnit\\Framework\\TestCase;101111#[CoversClass(SelectionList::class)]12#[CoversClass(SelectionList::class)]12final class SelectionListTest extends TestCase13final class SelectionListTest extends TestCase13{14{14-public function testGetEntityIds(): void15+private const int CHUNK_SIZE = 100;16+17+public function testAddEntityListAndGetAllIds(): void18+ {19+$selectionList = new SelectionList();20+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);21+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);22+23+$this->assertSame([1, 2, 3, 4], $selectionList->getAllIds());24+ }25+26+public function testAddEntityListMergesMultipleCallsForSamePriority(): void27+ {28+$selectionList = new SelectionList();29+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);30+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [3, 4]);31+32+$this->assertSame([1, 2, 3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));33+ }34+35+public function testGetEntityListItemsByGroup(): void36+ {37+$selectionList = new SelectionList();38+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);39+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);40+$selectionList->addEntityList(QueuePriorityEnum::LOW, [5, 6]);41+42+$this->assertSame([1, 2], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));43+$this->assertSame([3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::NORMAL));44+$this->assertSame([5, 6], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::LOW));45+ }46+47+public function testGetEntityListItemsByGroupReturnsEmptyArrayForUnknownGroup(): void15 {48 {16-$priority = ['p1', 'p2'];49+$selectionList = new SelectionList();17-$normal = ['n1', 'n2'];50+18-$selectionList = new SelectionList($priority, $normal);51+$this->assertSame([], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));52+ }195320-$this->assertSame($priority, $selectionList->getHighPriorityEntityIds());54+public function testGetEntityListGroups(): void21-$this->assertSame($normal, $selectionList->getNormalPriorityEntityId());55+ {56+$selectionList = new SelectionList();57+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);58+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2]);225923-$this->assertSame(['p1', 'p2', 'n1', 'n2'], $selectionList->getAllIds());60+$this->assertSame(['high', 'normal'], $selectionList->getEntityListGroups());24 }61 }256226public function testCountReturnsTotalCount(): void63public function testCountReturnsTotalCount(): void27 {64 {28-$selectionList = new SelectionList(['p1'], ['n1', 'n2']);65+$selectionList = new SelectionList();66+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);67+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2, 3]);68+29$this->assertSame(3, $selectionList->count());69$this->assertSame(3, $selectionList->count());30 }70 }317132-public function testIsEmptyReturnsTrueWhenBothListsAreEmpty(): void72+public function testIsEmptyReturnsTrueWhenNoEntitiesAdded(): void33 {73 {34-$selectionList = new SelectionList([], []);74+$selectionList = new SelectionList();75+35$this->assertTrue($selectionList->isEmpty());76$this->assertTrue($selectionList->isEmpty());36 }77 }377838-public function testIsEmptyReturnsFalseWhenAnyListIsNotEmpty(): void79+public function testIsEmptyReturnsFalseWhenEntitiesAdded(): void39 {80 {40-$selectionList = new SelectionList(['p1'], []);81+$selectionList = new SelectionList();41-$this->assertFalse($selectionList->isEmpty());82+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);428343-$selectionList2 = new SelectionList([], ['n1']);84+$this->assertFalse($selectionList->isEmpty());44-$this->assertFalse($selectionList2->isEmpty());45 }85 }468647-public function testIsStaleChunkSelected(): void87+public function testMarkStaleAndIsStaleChunkSelected(): void48 {88 {49-$selectionList = new SelectionList([], [], true);89+$selectionList = new SelectionList();50-$this->assertTrue($selectionList->isStaleChunkSelected());90+91+$this->assertFalse($selectionList->isStaleChunkSelected());92+93+$selectionList->markStale();519452-$selectionList2 = new SelectionList([], [], false);95+$this->assertTrue($selectionList->isStaleChunkSelected());53-$this->assertFalse($selectionList2->isStaleChunkSelected());54 }96 }559756public function testIsFullChunk(): void98public function testIsFullChunk(): void57 {99 {58-$chunkSize = 200;100+$selectionList = new SelectionList();59-101+$selectionList->setChunkSize(self::CHUNK_SIZE);60-$fullList = range(1, $chunkSize);102+61-$selectionList = new SelectionList(103+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, self::CHUNK_SIZE));62- priorityEntityIdList: $fullList,104+63- normalEntityIdList: [],105+$this->assertTrue($selectionList->isFullChunk());64- chunkSize: $chunkSize,106+ }65- );107+108+public function testIsNotFullChunkWhenBelowChunkSize(): void109+ {110+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);111+112+$selectionList = new SelectionList();113+$selectionList->setChunkSize(self::CHUNK_SIZE);114+115+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range(1, $halfRange));116+117+$this->assertFalse($selectionList->isFullChunk());118+ }119+120+public function testIsFullChunkAcrossMultiplePriorityGroups(): void121+ {122+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);123+124+$selectionList = new SelectionList();125+$selectionList->setChunkSize(self::CHUNK_SIZE);126+127+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, $halfRange));128+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range($halfRange + 1, self::CHUNK_SIZE));129+130+$this->assertTrue($selectionList->isFullChunk());131+ }132+133+public function testSetChunkSizeAffectsIsFullChunk(): void134+ {135+$selectionList = new SelectionList();136+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [1, 2, 3]);137+138+$selectionList->setChunkSize(3);66$this->assertTrue($selectionList->isFullChunk());139$this->assertTrue($selectionList->isFullChunk());6714068-$halfRange = (int) ceil($chunkSize / 2);141+$selectionList->setChunkSize(50);69-142+$this->assertFalse($selectionList->isFullChunk());70-$notFullList = range(1, $halfRange);71-$selectionList2 = new SelectionList(72- priorityEntityIdList: $notFullList,73- normalEntityIdList: [],74- chunkSize: $chunkSize,75- );76-$this->assertFalse($selectionList2->isFullChunk());77-78-$priorityRange = range(1, $halfRange);79-$normalRange = range($halfRange + 1, $chunkSize);80-81-$selectionList3 = new SelectionList(82- priorityEntityIdList: $priorityRange,83- normalEntityIdList: $normalRange,84- chunkSize: $chunkSize,85- );86-$this->assertTrue($selectionList3->isFullChunk());87 }143 }88}144}</selection>” selected.","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Expand","depth":21,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"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":"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":"Here is a precise and concise summary of the code selection, which refactors","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SelectionListTest","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"to accommodate a shift from fixed high/normal priority properties to a more dynamic, enum-driven priority group architecture.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Refactored Priority Handling","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Refactored Priority Handling","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Dynamic Priority Groups:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Replaces fixed high/normal array parameters with the","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"QueuePriorityEnum","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"HIGH","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"NORMAL","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"LOW","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"), allowing entity lists to be managed dynamically by group types.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Merged Registrations:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Validates that multiple","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"addEntityList()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"calls targeting the same priority level properly merge their data instead of overwriting it.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Group Querying:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Tests new methods","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"getEntityListItemsByGroup()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"and","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"getEntityListGroups()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"to retrieve group-specific IDs or an array of active group names (e.g.,","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"['high', 'normal']","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":").","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Updated State and Count Validations","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Updated State and Count Validations","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Instantiation:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Tests now instantiate","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SelectionList","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"without initial constructor arguments, using setters and action methods instead.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Empty States:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Updates assertions (","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"isEmpty()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":") to verify state based on whether any entities have been dynamically added, rather than checking pre-defined constructor arrays.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Stale Flags:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Changes from passing a","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"stale","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"boolean via the constructor to explicitly triggering a mutable","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$selectionList->markStale()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"method.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Chunk Capacity Behavior","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Chunk Capacity Behavior","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Flexible Chunk Sizes:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Introduces a","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"setChunkSize()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"method, replacing the constructor-configured chunk boundary.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Capacity Assertions:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Retains and updates the logic for","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"isFullChunk()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":", ensuring it accurately evaluates capacity when elements span multiple dynamic priority groups or when the chunk limit is altered mid-lifecycle.","depth":26,"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":"AXHeading","text":"You said Are there any issues or potential bolltenecks","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":"Are there any issues or potential bolltenecks","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":"Based on the test diff you provided, we can infer a few potential issues and architectural bottlenecks in the underlying","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SelectionList","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"implementation. While the tests are well-structured, the behavior they describe hints at a few areas you might want to keep an eye on, particularly for an Elasticsearch (ES) processor queue.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Here are the potential issues and bottlenecks to consider:","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"1. Array Merging Overhead (Performance)","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1. Array Merging Overhead (Performance)","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"testAddEntityListMergesMultipleCallsForSamePriority","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"test shows that calling","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"addEntityList()","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"multiple times for the same priority group merges the arrays.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The Bottleneck:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"If the underlying implementation uses","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"array_merge()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"inside a loop to append these IDs, it creates a new array in memory every time it's called. If you are processing thousands of entities and appending them in small batches, this can lead to memory bloat and CPU degradation due to constant array reallocation.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Mitigation:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Ensure the implementation handles batch appends efficiently (e.g., using the spread operator","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"[...$existing, ...$new]","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"or appending via references) or groups the arrays before doing a single merge.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"2. Lack of Uniqueness/Deduplication (Logic)","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2. Lack of Uniqueness/Deduplication (Logic)","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"None of the tests explicitly verify what happens if duplicate IDs are added. For example, if you call","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"addEntityList(QueuePriorityEnum::HIGH, [1, 2])","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"and then","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"addEntityList(QueuePriorityEnum::HIGH, [2, 3])","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":".","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The Issue:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Does the getter return","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"[1, 2, 2, 3]","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"or","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"[1, 2, 3]","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"? If duplicates are not filtered out, your ES processor might end up indexing the same entity multiple times in a single chunk, which wastes I/O and processor cycles.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Mitigation:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The underlying class should ideally enforce uniqueness (e.g., using","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"array_unique()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"before resolving the chunk, or using ID keys as associative array keys to naturally prevent duplicates).","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"3. Memory Consumption with Large Chunks (Scalability)","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3. Memory Consumption with Large Chunks (Scalability)","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The tests introduce","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"setChunkSize()","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":". If this chunk size is configured to be very large (e.g., tens of thousands of IDs to bulk-send to Elasticsearch).","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The Bottleneck:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Holding massive arrays of IDs in memory across different priority groups can quickly hit PHP memory limits, especially if this","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SelectionList","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"object is kept alive during a long-running daemon or cron job.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Mitigation:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Monitor memory usage if","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"CHUNK_SIZE","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"grows, and ensure the","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SelectionList","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"object is properly destroyed (or garbage collected) after the chunk is processed to free up memory.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"4. Type Juggling","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"4. Type Juggling","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"In the original code, string IDs were used (","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"['p1', 'p2']","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"). In the refactored tests, integer IDs are used (","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"[1, 2]","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":").","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The Issue:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"If your system handles UUIDs (strings) vs. relational DB auto-increments (integers), make sure the underlying implementation uses strict comparisons (","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"===","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":") where necessary, especially if deduplicating arrays, to prevent PHP from juggling","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"'1'","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"and","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"improperly.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Would you like me to draft a quick test case to check how the class currently handles duplicate IDs, or is deduplication intentionally handled further down your pipeline?","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}]...
|
-6919392816584860190
|
8165702397781963157
|
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
Copy prompt
You said I’m on page “<tabTitle>JY-20808 low priority indexing queue by Vasil-Jimi</tabTitle>” with “<selection>@@ -5,84 +5,140 @@5namespace Tests\Unit\Component\ES\Processor\DTOs;5namespace Tests\Unit\Component\ES\Processor\DTOs;667use Jiminny\Component\ES\Processor\DTOs\SelectionList;7use Jiminny\Component\ES\Processor\DTOs\SelectionList;8+use Jiminny\Component\ES\QueuePriorityEnum;8use PHPUnit\Framework\Attributes\CoversClass;9use PHPUnit\Framework\Attributes\CoversClass;9use PHPUnit\Framework\TestCase;10use PHPUnit\Framework\TestCase;101111#[CoversClass(SelectionList::class)]12#[CoversClass(SelectionList::class)]12final class SelectionListTest extends TestCase13final class SelectionListTest extends TestCase13{14{14-public function testGetEntityIds(): void15+private const int CHUNK_SIZE = 100;16+17+public function testAddEntityListAndGetAllIds(): void18+ {19+$selectionList = new SelectionList();20+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);21+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);22+23+$this->assertSame([1, 2, 3, 4], $selectionList->getAllIds());24+ }25+26+public function testAddEntityListMergesMultipleCallsForSamePriority(): void27+ {28+$selectionList = new SelectionList();29+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);30+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [3, 4]);31+32+$this->assertSame([1, 2, 3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));33+ }34+35+public function testGetEntityListItemsByGroup(): void36+ {37+$selectionList = new SelectionList();38+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);39+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);40+$selectionList->addEntityList(QueuePriorityEnum::LOW, [5, 6]);41+42+$this->assertSame([1, 2], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));43+$this->assertSame([3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::NORMAL));44+$this->assertSame([5, 6], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::LOW));45+ }46+47+public function testGetEntityListItemsByGroupReturnsEmptyArrayForUnknownGroup(): void15 {48 {16-$priority = ['p1', 'p2'];49+$selectionList = new SelectionList();17-$normal = ['n1', 'n2'];50+18-$selectionList = new SelectionList($priority, $normal);51+$this->assertSame([], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));52+ }195320-$this->assertSame($priority, $selectionList->getHighPriorityEntityIds());54+public function testGetEntityListGroups(): void21-$this->assertSame($normal, $selectionList->getNormalPriorityEntityId());55+ {56+$selectionList = new SelectionList();57+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);58+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2]);225923-$this->assertSame(['p1', 'p2', 'n1', 'n2'], $selectionList->getAllIds());60+$this->assertSame(['high', 'normal'], $selectionList->getEntityListGroups());24 }61 }256226public function testCountReturnsTotalCount(): void63public function testCountReturnsTotalCount(): void27 {64 {28-$selectionList = new SelectionList(['p1'], ['n1', 'n2']);65+$selectionList = new SelectionList();66+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);67+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2, 3]);68+29$this->assertSame(3, $selectionList->count());69$this->assertSame(3, $selectionList->count());30 }70 }317132-public function testIsEmptyReturnsTrueWhenBothListsAreEmpty(): void72+public function testIsEmptyReturnsTrueWhenNoEntitiesAdded(): void33 {73 {34-$selectionList = new SelectionList([], []);74+$selectionList = new SelectionList();75+35$this->assertTrue($selectionList->isEmpty());76$this->assertTrue($selectionList->isEmpty());36 }77 }377838-public function testIsEmptyReturnsFalseWhenAnyListIsNotEmpty(): void79+public function testIsEmptyReturnsFalseWhenEntitiesAdded(): void39 {80 {40-$selectionList = new SelectionList(['p1'], []);81+$selectionList = new SelectionList();41-$this->assertFalse($selectionList->isEmpty());82+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);428343-$selectionList2 = new SelectionList([], ['n1']);84+$this->assertFalse($selectionList->isEmpty());44-$this->assertFalse($selectionList2->isEmpty());45 }85 }468647-public function testIsStaleChunkSelected(): void87+public function testMarkStaleAndIsStaleChunkSelected(): void48 {88 {49-$selectionList = new SelectionList([], [], true);89+$selectionList = new SelectionList();50-$this->assertTrue($selectionList->isStaleChunkSelected());90+91+$this->assertFalse($selectionList->isStaleChunkSelected());92+93+$selectionList->markStale();519452-$selectionList2 = new SelectionList([], [], false);95+$this->assertTrue($selectionList->isStaleChunkSelected());53-$this->assertFalse($selectionList2->isStaleChunkSelected());54 }96 }559756public function testIsFullChunk(): void98public function testIsFullChunk(): void57 {99 {58-$chunkSize = 200;100+$selectionList = new SelectionList();59-101+$selectionList->setChunkSize(self::CHUNK_SIZE);60-$fullList = range(1, $chunkSize);102+61-$selectionList = new SelectionList(103+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, self::CHUNK_SIZE));62- priorityEntityIdList: $fullList,104+63- normalEntityIdList: [],105+$this->assertTrue($selectionList->isFullChunk());64- chunkSize: $chunkSize,106+ }65- );107+108+public function testIsNotFullChunkWhenBelowChunkSize(): void109+ {110+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);111+112+$selectionList = new SelectionList();113+$selectionList->setChunkSize(self::CHUNK_SIZE);114+115+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range(1, $halfRange));116+117+$this->assertFalse($selectionList->isFullChunk());118+ }119+120+public function testIsFullChunkAcrossMultiplePriorityGroups(): void121+ {122+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);123+124+$selectionList = new SelectionList();125+$selectionList->setChunkSize(self::CHUNK_SIZE);126+127+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, $halfRange));128+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range($halfRange + 1, self::CHUNK_SIZE));129+130+$this->assertTrue($selectionList->isFullChunk());131+ }132+133+public function testSetChunkSizeAffectsIsFullChunk(): void134+ {135+$selectionList = new SelectionList();136+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [1, 2, 3]);137+138+$selectionList->setChunkSize(3);66$this->assertTrue($selectionList->isFullChunk());139$this->assertTrue($selectionList->isFullChunk());6714068-$halfRange = (int) ceil($chunkSize / 2);141+$selectionList->setChunkSize(50);69-142+$this->assertFalse($selectionList->isFullChunk());70-$notFullList = range(1, $halfRange);71-$selectionList2 = new SelectionList(72- priorityEntityIdList: $notFullList,73- normalEntityIdList: [],74- chunkSize: $chunkSize,75- );76-$this->assertFalse($selectionList2->isFullChunk());77-78-$priorityRange = range(1, $halfRange);79-$normalRange = range($halfRange + 1, $chunkSize);80-81-$selectionList3 = new SelectionList(82- priorityEntityIdList: $priorityRange,83- normalEntityIdList: $normalRange,84- chunkSize: $chunkSize,85- );86-$this->assertTrue($selectionList3->isFullChunk());87 }143 }88}144}</selection>” selected. Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
You said
I’m on page “<tabTitle>JY-20808 low priority indexing queue by Vasil-Jimi</tabTitle>” with “<selection>@@ -5,84 +5,140 @@5namespace Tests\Unit\Component\ES\Processor\DTOs;5namespace Tests\Unit\Component\ES\Processor\DTOs;667use Jiminny\Component\ES\Processor\DTOs\SelectionList;7use Jiminny\Component\ES\Processor\DTOs\SelectionList;8+use Jiminny\Component\ES\QueuePriorityEnum;8use PHPUnit\Framework\Attributes\CoversClass;9use PHPUnit\Framework\Attributes\CoversClass;9use PHPUnit\Framework\TestCase;10use PHPUnit\Framework\TestCase;101111#[CoversClass(SelectionList::class)]12#[CoversClass(SelectionList::class)]12final class SelectionListTest extends TestCase13final class SelectionListTest extends TestCase13{14{14-public function testGetEntityIds(): void15+private const int CHUNK_SIZE = 100;16+17+public function testAddEntityListAndGetAllIds(): void18+ {19+$selectionList = new SelectionList();20+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);21+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);22+23+$this->assertSame([1, 2, 3, 4], $selectionList->getAllIds());24+ }25+26+public function testAddEntityListMergesMultipleCallsForSamePriority(): void27+ {28+$selectionList = new SelectionList();29+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);30+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [3, 4]);31+32+$this->assertSame([1, 2, 3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));33+ }34+35+public function testGetEntityListItemsByGroup(): void36+ {37+$selectionList = new SelectionList();38+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);39+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);40+$selectionList->addEntityList(QueuePriorityEnum::LOW, [5, 6]);41+42+$this->assertSame([1, 2], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));43+$this->assertSame([3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::NORMAL));44+$this->assertSame([5, 6], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::LOW));45+ }46+47+public function testGetEntityListItemsByGroupReturnsEmptyArrayForUnknownGroup(): void15 {48 {16-$priority = ['p1', 'p2'];49+$selectionList = new SelectionList();17-$normal = ['n1', 'n2'];50+18-$selectionList = new SelectionList($priority, $normal);51+$this->assertSame([], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));52+ }195320-$this->assertSame($priority, $selectionList->getHighPriorityEntityIds());54+public function testGetEntityListGroups(): void21-$this->assertSame($normal, $selectionList->getNormalPriorityEntityId());55+ {56+$selectionList = new SelectionList();57+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);58+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2]);225923-$this->assertSame(['p1', 'p2', 'n1', 'n2'], $selectionList->getAllIds());60+$this->assertSame(['high', 'normal'], $selectionList->getEntityListGroups());24 }61 }256226public function testCountReturnsTotalCount(): void63public function testCountReturnsTotalCount(): void27 {64 {28-$selectionList = new SelectionList(['p1'], ['n1', 'n2']);65+$selectionList = new SelectionList();66+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);67+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2, 3]);68+29$this->assertSame(3, $selectionList->count());69$this->assertSame(3, $selectionList->count());30 }70 }317132-public function testIsEmptyReturnsTrueWhenBothListsAreEmpty(): void72+public function testIsEmptyReturnsTrueWhenNoEntitiesAdded(): void33 {73 {34-$selectionList = new SelectionList([], []);74+$selectionList = new SelectionList();75+35$this->assertTrue($selectionList->isEmpty());76$this->assertTrue($selectionList->isEmpty());36 }77 }377838-public function testIsEmptyReturnsFalseWhenAnyListIsNotEmpty(): void79+public function testIsEmptyReturnsFalseWhenEntitiesAdded(): void39 {80 {40-$selectionList = new SelectionList(['p1'], []);81+$selectionList = new SelectionList();41-$this->assertFalse($selectionList->isEmpty());82+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);428343-$selectionList2 = new SelectionList([], ['n1']);84+$this->assertFalse($selectionList->isEmpty());44-$this->assertFalse($selectionList2->isEmpty());45 }85 }468647-public function testIsStaleChunkSelected(): void87+public function testMarkStaleAndIsStaleChunkSelected(): void48 {88 {49-$selectionList = new SelectionList([], [], true);89+$selectionList = new SelectionList();50-$this->assertTrue($selectionList->isStaleChunkSelected());90+91+$this->assertFalse($selectionList->isStaleChunkSelected());92+93+$selectionList->markStale();519452-$selectionList2 = new SelectionList([], [], false);95+$this->assertTrue($selectionList->isStaleChunkSelected());53-$this->assertFalse($selectionList2->isStaleChunkSelected());54 }96 }559756public function testIsFullChunk(): void98public function testIsFullChunk(): void57 {99 {58-$chunkSize = 200;100+$selectionList = new SelectionList();59-101+$selectionList->setChunkSize(self::CHUNK_SIZE);60-$fullList = range(1, $chunkSize);102+61-$selectionList = new SelectionList(103+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, self::CHUNK_SIZE));62- priorityEntityIdList: $fullList,104+63- normalEntityIdList: [],105+$this->assertTrue($selectionList->isFullChunk());64- chunkSize: $chunkSize,106+ }65- );107+108+public function testIsNotFullChunkWhenBelowChunkSize(): void109+ {110+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);111+112+$selectionList = new SelectionList();113+$selectionList->setChunkSize(self::CHUNK_SIZE);114+115+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range(1, $halfRange));116+117+$this->assertFalse($selectionList->isFullChunk());118+ }119+120+public function testIsFullChunkAcrossMultiplePriorityGroups(): void121+ {122+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);123+124+$selectionList = new SelectionList();125+$selectionList->setChunkSize(self::CHUNK_SIZE);126+127+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, $halfRange));128+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range($halfRange + 1, self::CHUNK_SIZE));129+130+$this->assertTrue($selectionList->isFullChunk());131+ }132+133+public function testSetChunkSizeAffectsIsFullChunk(): void134+ {135+$selectionList = new SelectionList();136+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [1, 2, 3]);137+138+$selectionList->setChunkSize(3);66$this->assertTrue($selectionList->isFullChunk());139$this->assertTrue($selectionList->isFullChunk());6714068-$halfRange = (int) ceil($chunkSize / 2);141+$selectionList->setChunkSize(50);69-142+$this->assertFalse($selectionList->isFullChunk());70-$notFullList = range(1, $halfRange);71-$selectionList2 = new SelectionList(72- priorityEntityIdList: $notFullList,73- normalEntityIdList: [],74- chunkSize: $chunkSize,75- );76-$this->assertFalse($selectionList2->isFullChunk());77-78-$priorityRange = range(1, $halfRange);79-$normalRange = range($halfRange + 1, $chunkSize);80-81-$selectionList3 = new SelectionList(82- priorityEntityIdList: $priorityRange,83- normalEntityIdList: $normalRange,84- chunkSize: $chunkSize,85- );86-$this->assertTrue($selectionList3->isFullChunk());87 }143 }88}144}</selection>” selected.
Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
Expand
Listen
Gemini said
Gemini said
Here is a precise and concise summary of the code selection, which refactors
SelectionListTest
to accommodate a shift from fixed high/normal priority properties to a more dynamic, enum-driven priority group architecture.
Refactored Priority Handling
Refactored Priority Handling
Dynamic Priority Groups:
Replaces fixed high/normal array parameters with the
QueuePriorityEnum
(
HIGH
,
NORMAL
,
LOW
), allowing entity lists to be managed dynamically by group types.
Merged Registrations:
Validates that multiple
addEntityList()
calls targeting the same priority level properly merge their data instead of overwriting it.
Group Querying:
Tests new methods
getEntityListItemsByGroup()
and
getEntityListGroups()
to retrieve group-specific IDs or an array of active group names (e.g.,
['high', 'normal']
).
Updated State and Count Validations
Updated State and Count Validations
Instantiation:
Tests now instantiate
SelectionList
without initial constructor arguments, using setters and action methods instead.
Empty States:
Updates assertions (
isEmpty()
) to verify state based on whether any entities have been dynamically added, rather than checking pre-defined constructor arrays.
Stale Flags:
Changes from passing a
stale
boolean via the constructor to explicitly triggering a mutable
$selectionList->markStale()
method.
Chunk Capacity Behavior
Chunk Capacity Behavior
Flexible Chunk Sizes:
Introduces a
setChunkSize()
method, replacing the constructor-configured chunk boundary.
Capacity Assertions:
Retains and updates the logic for
isFullChunk()
, ensuring it accurately evaluates capacity when elements span multiple dynamic priority groups or when the chunk limit is altered mid-lifecycle.
Good response
Bad response
Share & export
Copy
Show more options
Copy prompt
You said Are there any issues or potential bolltenecks
You said
Are there any issues or potential bolltenecks
Listen
Show thinking
Gemini said
Gemini said
Based on the test diff you provided, we can infer a few potential issues and architectural bottlenecks in the underlying
SelectionList
implementation. While the tests are well-structured, the behavior they describe hints at a few areas you might want to keep an eye on, particularly for an Elasticsearch (ES) processor queue.
Here are the potential issues and bottlenecks to consider:
1. Array Merging Overhead (Performance)
1. Array Merging Overhead (Performance)
The
testAddEntityListMergesMultipleCallsForSamePriority
test shows that calling
addEntityList()
multiple times for the same priority group merges the arrays.
The Bottleneck:
If the underlying implementation uses
array_merge()
inside a loop to append these IDs, it creates a new array in memory every time it's called. If you are processing thousands of entities and appending them in small batches, this can lead to memory bloat and CPU degradation due to constant array reallocation.
Mitigation:
Ensure the implementation handles batch appends efficiently (e.g., using the spread operator
[...$existing, ...$new]
or appending via references) or groups the arrays before doing a single merge.
2. Lack of Uniqueness/Deduplication (Logic)
2. Lack of Uniqueness/Deduplication (Logic)
None of the tests explicitly verify what happens if duplicate IDs are added. For example, if you call
addEntityList(QueuePriorityEnum::HIGH, [1, 2])
and then
addEntityList(QueuePriorityEnum::HIGH, [2, 3])
.
The Issue:
Does the getter return
[1, 2, 2, 3]
or
[1, 2, 3]
? If duplicates are not filtered out, your ES processor might end up indexing the same entity multiple times in a single chunk, which wastes I/O and processor cycles.
Mitigation:
The underlying class should ideally enforce uniqueness (e.g., using
array_unique()
before resolving the chunk, or using ID keys as associative array keys to naturally prevent duplicates).
3. Memory Consumption with Large Chunks (Scalability)
3. Memory Consumption with Large Chunks (Scalability)
The tests introduce
setChunkSize()
. If this chunk size is configured to be very large (e.g., tens of thousands of IDs to bulk-send to Elasticsearch).
The Bottleneck:
Holding massive arrays of IDs in memory across different priority groups can quickly hit PHP memory limits, especially if this
SelectionList
object is kept alive during a long-running daemon or cron job.
Mitigation:
Monitor memory usage if
CHUNK_SIZE
grows, and ensure the
SelectionList
object is properly destroyed (or garbage collected) after the chunk is processed to free up memory.
4. Type Juggling
4. Type Juggling
In the original code, string IDs were used (
['p1', 'p2']
). In the refactored tests, integer IDs are used (
[1, 2]
).
The Issue:
If your system handles UUIDs (strings) vs. relational DB auto-increments (integers), make sure the underlying implementation uses strict comparisons (
===
) where necessary, especially if deduplicating arrays, to prevent PHP from juggling
'1'
and
1
improperly.
Would you like me to draft a quick test case to check how the class currently handles duplicate IDs, or is deduplication intentionally handled further down your pipeline?
Good response
Bad response
Share & export
Copy
Show more options...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
55662
|
1933
|
0
|
2026-05-19T06:37:27.449725+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779172647449_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
Copy prompt
Edit
You said I’m on page “<tabTitle>JY-20808 low priority indexing queue by Vasil-Jimi</tabTitle>” with “<selection>@@ -5,84 +5,140 @@5namespace Tests\Unit\Component\ES\Processor\DTOs;5namespace Tests\Unit\Component\ES\Processor\DTOs;667use Jiminny\Component\ES\Processor\DTOs\SelectionList;7use Jiminny\Component\ES\Processor\DTOs\SelectionList;8+use Jiminny\Component\ES\QueuePriorityEnum;8use PHPUnit\Framework\Attributes\CoversClass;9use PHPUnit\Framework\Attributes\CoversClass;9use PHPUnit\Framework\TestCase;10use PHPUnit\Framework\TestCase;101111#[CoversClass(SelectionList::class)]12#[CoversClass(SelectionList::class)]12final class SelectionListTest extends TestCase13final class SelectionListTest extends TestCase13{14{14-public function testGetEntityIds(): void15+private const int CHUNK_SIZE = 100;16+17+public function testAddEntityListAndGetAllIds(): void18+ {19+$selectionList = new SelectionList();20+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);21+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);22+23+$this->assertSame([1, 2, 3, 4], $selectionList->getAllIds());24+ }25+26+public function testAddEntityListMergesMultipleCallsForSamePriority(): void27+ {28+$selectionList = new SelectionList();29+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);30+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [3, 4]);31+32+$this->assertSame([1, 2, 3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));33+ }34+35+public function testGetEntityListItemsByGroup(): void36+ {37+$selectionList = new SelectionList();38+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);39+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);40+$selectionList->addEntityList(QueuePriorityEnum::LOW, [5, 6]);41+42+$this->assertSame([1, 2], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));43+$this->assertSame([3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::NORMAL));44+$this->assertSame([5, 6], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::LOW));45+ }46+47+public function testGetEntityListItemsByGroupReturnsEmptyArrayForUnknownGroup(): void15 {48 {16-$priority = ['p1', 'p2'];49+$selectionList = new SelectionList();17-$normal = ['n1', 'n2'];50+18-$selectionList = new SelectionList($priority, $normal);51+$this->assertSame([], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));52+ }195320-$this->assertSame($priority, $selectionList->getHighPriorityEntityIds());54+public function testGetEntityListGroups(): void21-$this->assertSame($normal, $selectionList->getNormalPriorityEntityId());55+ {56+$selectionList = new SelectionList();57+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);58+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2]);225923-$this->assertSame(['p1', 'p2', 'n1', 'n2'], $selectionList->getAllIds());60+$this->assertSame(['high', 'normal'], $selectionList->getEntityListGroups());24 }61 }256226public function testCountReturnsTotalCount(): void63public function testCountReturnsTotalCount(): void27 {64 {28-$selectionList = new SelectionList(['p1'], ['n1', 'n2']);65+$selectionList = new SelectionList();66+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);67+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2, 3]);68+29$this->assertSame(3, $selectionList->count());69$this->assertSame(3, $selectionList->count());30 }70 }317132-public function testIsEmptyReturnsTrueWhenBothListsAreEmpty(): void72+public function testIsEmptyReturnsTrueWhenNoEntitiesAdded(): void33 {73 {34-$selectionList = new SelectionList([], []);74+$selectionList = new SelectionList();75+35$this->assertTrue($selectionList->isEmpty());76$this->assertTrue($selectionList->isEmpty());36 }77 }377838-public function testIsEmptyReturnsFalseWhenAnyListIsNotEmpty(): void79+public function testIsEmptyReturnsFalseWhenEntitiesAdded(): void39 {80 {40-$selectionList = new SelectionList(['p1'], []);81+$selectionList = new SelectionList();41-$this->assertFalse($selectionList->isEmpty());82+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);428343-$selectionList2 = new SelectionList([], ['n1']);84+$this->assertFalse($selectionList->isEmpty());44-$this->assertFalse($selectionList2->isEmpty());45 }85 }468647-public function testIsStaleChunkSelected(): void87+public function testMarkStaleAndIsStaleChunkSelected(): void48 {88 {49-$selectionList = new SelectionList([], [], true);89+$selectionList = new SelectionList();50-$this->assertTrue($selectionList->isStaleChunkSelected());90+91+$this->assertFalse($selectionList->isStaleChunkSelected());92+93+$selectionList->markStale();519452-$selectionList2 = new SelectionList([], [], false);95+$this->assertTrue($selectionList->isStaleChunkSelected());53-$this->assertFalse($selectionList2->isStaleChunkSelected());54 }96 }559756public function testIsFullChunk(): void98public function testIsFullChunk(): void57 {99 {58-$chunkSize = 200;100+$selectionList = new SelectionList();59-101+$selectionList->setChunkSize(self::CHUNK_SIZE);60-$fullList = range(1, $chunkSize);102+61-$selectionList = new SelectionList(103+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, self::CHUNK_SIZE));62- priorityEntityIdList: $fullList,104+63- normalEntityIdList: [],105+$this->assertTrue($selectionList->isFullChunk());64- chunkSize: $chunkSize,106+ }65- );107+108+public function testIsNotFullChunkWhenBelowChunkSize(): void109+ {110+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);111+112+$selectionList = new SelectionList();113+$selectionList->setChunkSize(self::CHUNK_SIZE);114+115+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range(1, $halfRange));116+117+$this->assertFalse($selectionList->isFullChunk());118+ }119+120+public function testIsFullChunkAcrossMultiplePriorityGroups(): void121+ {122+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);123+124+$selectionList = new SelectionList();125+$selectionList->setChunkSize(self::CHUNK_SIZE);126+127+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, $halfRange));128+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range($halfRange + 1, self::CHUNK_SIZE));129+130+$this->assertTrue($selectionList->isFullChunk());131+ }132+133+public function testSetChunkSizeAffectsIsFullChunk(): void134+ {135+$selectionList = new SelectionList();136+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [1, 2, 3]);137+138+$selectionList->setChunkSize(3);66$this->assertTrue($selectionList->isFullChunk());139$this->assertTrue($selectionList->isFullChunk());6714068-$halfRange = (int) ceil($chunkSize / 2);141+$selectionList->setChunkSize(50);69-142+$this->assertFalse($selectionList->isFullChunk());70-$notFullList = range(1, $halfRange);71-$selectionList2 = new SelectionList(72- priorityEntityIdList: $notFullList,73- normalEntityIdList: [],74- chunkSize: $chunkSize,75- );76-$this->assertFalse($selectionList2->isFullChunk());77-78-$priorityRange = range(1, $halfRange);79-$normalRange = range($halfRange + 1, $chunkSize);80-81-$selectionList3 = new SelectionList(82- priorityEntityIdList: $priorityRange,83- normalEntityIdList: $normalRange,84- chunkSize: $chunkSize,85- );86-$this->assertTrue($selectionList3->isFullChunk());87 }143 }88}144}</selection>” selected. Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
You said
I’m on page “<tabTitle>JY-20808 low priority indexing queue by Vasil-Jimi</tabTitle>” with “<selection>@@ -5,84 +5,140 @@5namespace Tests\Unit\Component\ES\Processor\DTOs;5namespace Tests\Unit\Component\ES\Processor\DTOs;667use Jiminny\Component\ES\Processor\DTOs\SelectionList;7use Jiminny\Component\ES\Processor\DTOs\SelectionList;8+use Jiminny\Component\ES\QueuePriorityEnum;8use PHPUnit\Framework\Attributes\CoversClass;9use PHPUnit\Framework\Attributes\CoversClass;9use PHPUnit\Framework\TestCase;10use PHPUnit\Framework\TestCase;101111#[CoversClass(SelectionList::class)]12#[CoversClass(SelectionList::class)]12final class SelectionListTest extends TestCase13final class SelectionListTest extends TestCase13{14{14-public function testGetEntityIds(): void15+private const int CHUNK_SIZE = 100;16+17+public function testAddEntityListAndGetAllIds(): void18+ {19+$selectionList = new SelectionList();20+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);21+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);22+23+$this->assertSame([1, 2, 3, 4], $selectionList->getAllIds());24+ }25+26+public function testAddEntityListMergesMultipleCallsForSamePriority(): void27+ {28+$selectionList = new SelectionList();29+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);30+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [3, 4]);31+32+$this->assertSame([1, 2, 3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));33+ }34+35+public function testGetEntityListItemsByGroup(): void36+ {37+$selectionList = new SelectionList();38+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);39+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);40+$selectionList->addEntityList(QueuePriorityEnum::LOW, [5, 6]);41+42+$this->assertSame([1, 2], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));43+$this->assertSame([3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::NORMAL));44+$this->assertSame([5, 6], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::LOW));45+ }46+47+public function testGetEntityListItemsByGroupReturnsEmptyArrayForUnknownGroup(): void15 {48 {16-$priority = ['p1', 'p2'];49+$selectionList = new SelectionList();17-$normal = ['n1', 'n2'];50+18-$selectionList = new SelectionList($priority, $normal);51+$this->assertSame([], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));52+ }195320-$this->assertSame($priority, $selectionList->getHighPriorityEntityIds());54+public function testGetEntityListGroups(): void21-$this->assertSame($normal, $selectionList->getNormalPriorityEntityId());55+ {56+$selectionList = new SelectionList();57+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);58+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2]);225923-$this->assertSame(['p1', 'p2', 'n1', 'n2'], $selectionList->getAllIds());60+$this->assertSame(['high', 'normal'], $selectionList->getEntityListGroups());24 }61 }256226public function testCountReturnsTotalCount(): void63public function testCountReturnsTotalCount(): void27 {64 {28-$selectionList = new SelectionList(['p1'], ['n1', 'n2']);65+$selectionList = new SelectionList();66+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);67+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2, 3]);68+29$this->assertSame(3, $selectionList->count());69$this->assertSame(3, $selectionList->count());30 }70 }317132-public function testIsEmptyReturnsTrueWhenBothListsAreEmpty(): void72+public function testIsEmptyReturnsTrueWhenNoEntitiesAdded(): void33 {73 {34-$selectionList = new SelectionList([], []);74+$selectionList = new SelectionList();75+35$this->assertTrue($selectionList->isEmpty());76$this->assertTrue($selectionList->isEmpty());36 }77 }377838-public function testIsEmptyReturnsFalseWhenAnyListIsNotEmpty(): void79+public function testIsEmptyReturnsFalseWhenEntitiesAdded(): void39 {80 {40-$selectionList = new SelectionList(['p1'], []);81+$selectionList = new SelectionList();41-$this->assertFalse($selectionList->isEmpty());82+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);428343-$selectionList2 = new SelectionList([], ['n1']);84+$this->assertFalse($selectionList->isEmpty());44-$this->assertFalse($selectionList2->isEmpty());45 }85 }468647-public function testIsStaleChunkSelected(): void87+public function testMarkStaleAndIsStaleChunkSelected(): void48 {88 {49-$selectionList = new SelectionList([], [], true);89+$selectionList = new SelectionList();50-$this->assertTrue($selectionList->isStaleChunkSelected());90+91+$this->assertFalse($selectionList->isStaleChunkSelected());92+93+$selectionList->markStale();519452-$selectionList2 = new SelectionList([], [], false);95+$this->assertTrue($selectionList->isStaleChunkSelected());53-$this->assertFalse($selectionList2->isStaleChunkSelected());54 }96 }559756public function testIsFullChunk(): void98public function testIsFullChunk(): void57 {99 {58-$chunkSize = 200;100+$selectionList = new SelectionList();59-101+$selectionList->setChunkSize(self::CHUNK_SIZE);60-$fullList = range(1, $chunkSize);102+61-$selectionList = new SelectionList(103+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, self::CHUNK_SIZE));62- priorityEntityIdList: $fullList,104+63- normalEntityIdList: [],105+$this->assertTrue($selectionList->isFullChunk());64- chunkSize: $chunkSize,106+ }65- );107+108+public function testIsNotFullChunkWhenBelowChunkSize(): void109+ {110+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);111+112+$selectionList = new SelectionList();113+$selectionList->setChunkSize(self::CHUNK_SIZE);114+115+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range(1, $halfRange));116+117+$this->assertFalse($selectionList->isFullChunk());118+ }119+120+public function testIsFullChunkAcrossMultiplePriorityGroups(): void121+ {122+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);123+124+$selectionList = new SelectionList();125+$selectionList->setChunkSize(self::CHUNK_SIZE);126+127+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, $halfRange));128+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range($halfRange + 1, self::CHUNK_SIZE));129+130+$this->assertTrue($selectionList->isFullChunk());131+ }132+133+public function testSetChunkSizeAffectsIsFullChunk(): void134+ {135+$selectionList = new SelectionList();136+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [1, 2, 3]);137+138+$selectionList->setChunkSize(3);66$this->assertTrue($selectionList->isFullChunk());139$this->assertTrue($selectionList->isFullChunk());6714068-$halfRange = (int) ceil($chunkSize / 2);141+$selectionList->setChunkSize(50);69-142+$this->assertFalse($selectionList->isFullChunk());70-$notFullList = range(1, $halfRange);71-$selectionList2 = new SelectionList(72- priorityEntityIdList: $notFullList,73- normalEntityIdList: [],74- chunkSize: $chunkSize,75- );76-$this->assertFalse($selectionList2->isFullChunk());77-78-$priorityRange = range(1, $halfRange);79-$normalRange = range($halfRange + 1, $chunkSize);80-81-$selectionList3 = new SelectionList(82- priorityEntityIdList: $priorityRange,83- normalEntityIdList: $normalRange,84- chunkSize: $chunkSize,85- );86-$this->assertTrue($selectionList3->isFullChunk());87 }143 }88}144}</selection>” selected.
Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
Expand
Listen
Show thinking
Gemini said
Gemini said
Here is a summary of the changes made to the
SelectionListTest
file, reflecting a significant refactoring of how the
SelectionList
class manages state and priorities.
Object Instantiation and State Management
Object Instantiation and State Management
Removed Constructor Injection:
The tests no longer pass arrays, chunk sizes, or boolean flags directly into the
SelectionList
constructor. Objects are now instantiated empty (
new SelectionList()
).
Introduced
addEntityList()
:
Added tests for populating the selection list dynamically using
addEntityList()
, which pairs a
QueuePriorityEnum
(e.g.,
HIGH
,
NORMAL
,
LOW
) with an array of IDs.
Merged Priorities:
Added tests confirming that invoking
addEntityList()
multiple times for the same priority group successfully merges the ID arrays.
Updated Data Retrieval
Updated Data Retrieval
Generic Group Getters:
Removed legacy priority-specific getters (e.g.,
getHighPriorityEntityIds()
). These are replaced by tests for
getEntityListItemsByGroup()
, which fetches IDs based on the provided enum.
Unknown Group Handling:
Added validation that
getEntityListItemsByGroup()
safely returns an empty array when querying an unpopulated priority group.
Group Listing:
Added
testGetEntityListGroups()
to verify the retrieval of all active priority group keys (e.g.,
['high', 'normal']
).
Aggregated Fetching:
Maintained and updated tests for
getAllIds()
to ensure it correctly flattens IDs across all newly structured priority groups.
Chunking and Flags
Chunking and Flags
Dynamic Chunk Sizing:
Introduced a
CHUNK_SIZE
constant and replaced constructor-based chunk sizing with a new
setChunkSize()
method.
Chunk Validation:
Expanded
isFullChunk()
tests to verify behavior when exactly at chunk capacity, below capacity, when capacities are split across multiple priority groups, and when the chunk size is changed dynamically.
Stale Status:
Replaced the constructor-injected stale flag with a new
markStale()
method, testing that
isStaleChunkSelected()
correctly toggles from false to true.
Utility Methods:
Updated tests for
count()
and
isEmpty()
to align with the new
addEntityList
structure rather than constructor arrays.
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...
|
[{"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":"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 I’m on page “<tabTitle>JY-20808 low priority indexing queue by Vasil-Jimi</tabTitle>” with “<selection>@@ -5,84 +5,140 @@5namespace Tests\\Unit\\Component\\ES\\Processor\\DTOs;5namespace Tests\\Unit\\Component\\ES\\Processor\\DTOs;667use Jiminny\\Component\\ES\\Processor\\DTOs\\SelectionList;7use Jiminny\\Component\\ES\\Processor\\DTOs\\SelectionList;8+use Jiminny\\Component\\ES\\QueuePriorityEnum;8use PHPUnit\\Framework\\Attributes\\CoversClass;9use PHPUnit\\Framework\\Attributes\\CoversClass;9use PHPUnit\\Framework\\TestCase;10use PHPUnit\\Framework\\TestCase;101111#[CoversClass(SelectionList::class)]12#[CoversClass(SelectionList::class)]12final class SelectionListTest extends TestCase13final class SelectionListTest extends TestCase13{14{14-public function testGetEntityIds(): void15+private const int CHUNK_SIZE = 100;16+17+public function testAddEntityListAndGetAllIds(): void18+ {19+$selectionList = new SelectionList();20+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);21+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);22+23+$this->assertSame([1, 2, 3, 4], $selectionList->getAllIds());24+ }25+26+public function testAddEntityListMergesMultipleCallsForSamePriority(): void27+ {28+$selectionList = new SelectionList();29+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);30+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [3, 4]);31+32+$this->assertSame([1, 2, 3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));33+ }34+35+public function testGetEntityListItemsByGroup(): void36+ {37+$selectionList = new SelectionList();38+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);39+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);40+$selectionList->addEntityList(QueuePriorityEnum::LOW, [5, 6]);41+42+$this->assertSame([1, 2], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));43+$this->assertSame([3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::NORMAL));44+$this->assertSame([5, 6], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::LOW));45+ }46+47+public function testGetEntityListItemsByGroupReturnsEmptyArrayForUnknownGroup(): void15 {48 {16-$priority = ['p1', 'p2'];49+$selectionList = new SelectionList();17-$normal = ['n1', 'n2'];50+18-$selectionList = new SelectionList($priority, $normal);51+$this->assertSame([], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));52+ }195320-$this->assertSame($priority, $selectionList->getHighPriorityEntityIds());54+public function testGetEntityListGroups(): void21-$this->assertSame($normal, $selectionList->getNormalPriorityEntityId());55+ {56+$selectionList = new SelectionList();57+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);58+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2]);225923-$this->assertSame(['p1', 'p2', 'n1', 'n2'], $selectionList->getAllIds());60+$this->assertSame(['high', 'normal'], $selectionList->getEntityListGroups());24 }61 }256226public function testCountReturnsTotalCount(): void63public function testCountReturnsTotalCount(): void27 {64 {28-$selectionList = new SelectionList(['p1'], ['n1', 'n2']);65+$selectionList = new SelectionList();66+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);67+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2, 3]);68+29$this->assertSame(3, $selectionList->count());69$this->assertSame(3, $selectionList->count());30 }70 }317132-public function testIsEmptyReturnsTrueWhenBothListsAreEmpty(): void72+public function testIsEmptyReturnsTrueWhenNoEntitiesAdded(): void33 {73 {34-$selectionList = new SelectionList([], []);74+$selectionList = new SelectionList();75+35$this->assertTrue($selectionList->isEmpty());76$this->assertTrue($selectionList->isEmpty());36 }77 }377838-public function testIsEmptyReturnsFalseWhenAnyListIsNotEmpty(): void79+public function testIsEmptyReturnsFalseWhenEntitiesAdded(): void39 {80 {40-$selectionList = new SelectionList(['p1'], []);81+$selectionList = new SelectionList();41-$this->assertFalse($selectionList->isEmpty());82+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);428343-$selectionList2 = new SelectionList([], ['n1']);84+$this->assertFalse($selectionList->isEmpty());44-$this->assertFalse($selectionList2->isEmpty());45 }85 }468647-public function testIsStaleChunkSelected(): void87+public function testMarkStaleAndIsStaleChunkSelected(): void48 {88 {49-$selectionList = new SelectionList([], [], true);89+$selectionList = new SelectionList();50-$this->assertTrue($selectionList->isStaleChunkSelected());90+91+$this->assertFalse($selectionList->isStaleChunkSelected());92+93+$selectionList->markStale();519452-$selectionList2 = new SelectionList([], [], false);95+$this->assertTrue($selectionList->isStaleChunkSelected());53-$this->assertFalse($selectionList2->isStaleChunkSelected());54 }96 }559756public function testIsFullChunk(): void98public function testIsFullChunk(): void57 {99 {58-$chunkSize = 200;100+$selectionList = new SelectionList();59-101+$selectionList->setChunkSize(self::CHUNK_SIZE);60-$fullList = range(1, $chunkSize);102+61-$selectionList = new SelectionList(103+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, self::CHUNK_SIZE));62- priorityEntityIdList: $fullList,104+63- normalEntityIdList: [],105+$this->assertTrue($selectionList->isFullChunk());64- chunkSize: $chunkSize,106+ }65- );107+108+public function testIsNotFullChunkWhenBelowChunkSize(): void109+ {110+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);111+112+$selectionList = new SelectionList();113+$selectionList->setChunkSize(self::CHUNK_SIZE);114+115+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range(1, $halfRange));116+117+$this->assertFalse($selectionList->isFullChunk());118+ }119+120+public function testIsFullChunkAcrossMultiplePriorityGroups(): void121+ {122+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);123+124+$selectionList = new SelectionList();125+$selectionList->setChunkSize(self::CHUNK_SIZE);126+127+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, $halfRange));128+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range($halfRange + 1, self::CHUNK_SIZE));129+130+$this->assertTrue($selectionList->isFullChunk());131+ }132+133+public function testSetChunkSizeAffectsIsFullChunk(): void134+ {135+$selectionList = new SelectionList();136+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [1, 2, 3]);137+138+$selectionList->setChunkSize(3);66$this->assertTrue($selectionList->isFullChunk());139$this->assertTrue($selectionList->isFullChunk());6714068-$halfRange = (int) ceil($chunkSize / 2);141+$selectionList->setChunkSize(50);69-142+$this->assertFalse($selectionList->isFullChunk());70-$notFullList = range(1, $halfRange);71-$selectionList2 = new SelectionList(72- priorityEntityIdList: $notFullList,73- normalEntityIdList: [],74- chunkSize: $chunkSize,75- );76-$this->assertFalse($selectionList2->isFullChunk());77-78-$priorityRange = range(1, $halfRange);79-$normalRange = range($halfRange + 1, $chunkSize);80-81-$selectionList3 = new SelectionList(82- priorityEntityIdList: $priorityRange,83- normalEntityIdList: $normalRange,84- chunkSize: $chunkSize,85- );86-$this->assertTrue($selectionList3->isFullChunk());87 }143 }88}144}</selection>” selected. Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.","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":"I’m on page “<tabTitle>JY-20808 low priority indexing queue by Vasil-Jimi</tabTitle>” with “<selection>@@ -5,84 +5,140 @@5namespace Tests\\Unit\\Component\\ES\\Processor\\DTOs;5namespace Tests\\Unit\\Component\\ES\\Processor\\DTOs;667use Jiminny\\Component\\ES\\Processor\\DTOs\\SelectionList;7use Jiminny\\Component\\ES\\Processor\\DTOs\\SelectionList;8+use Jiminny\\Component\\ES\\QueuePriorityEnum;8use PHPUnit\\Framework\\Attributes\\CoversClass;9use PHPUnit\\Framework\\Attributes\\CoversClass;9use PHPUnit\\Framework\\TestCase;10use PHPUnit\\Framework\\TestCase;101111#[CoversClass(SelectionList::class)]12#[CoversClass(SelectionList::class)]12final class SelectionListTest extends TestCase13final class SelectionListTest extends TestCase13{14{14-public function testGetEntityIds(): void15+private const int CHUNK_SIZE = 100;16+17+public function testAddEntityListAndGetAllIds(): void18+ {19+$selectionList = new SelectionList();20+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);21+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);22+23+$this->assertSame([1, 2, 3, 4], $selectionList->getAllIds());24+ }25+26+public function testAddEntityListMergesMultipleCallsForSamePriority(): void27+ {28+$selectionList = new SelectionList();29+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);30+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [3, 4]);31+32+$this->assertSame([1, 2, 3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));33+ }34+35+public function testGetEntityListItemsByGroup(): void36+ {37+$selectionList = new SelectionList();38+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);39+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);40+$selectionList->addEntityList(QueuePriorityEnum::LOW, [5, 6]);41+42+$this->assertSame([1, 2], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));43+$this->assertSame([3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::NORMAL));44+$this->assertSame([5, 6], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::LOW));45+ }46+47+public function testGetEntityListItemsByGroupReturnsEmptyArrayForUnknownGroup(): void15 {48 {16-$priority = ['p1', 'p2'];49+$selectionList = new SelectionList();17-$normal = ['n1', 'n2'];50+18-$selectionList = new SelectionList($priority, $normal);51+$this->assertSame([], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));52+ }195320-$this->assertSame($priority, $selectionList->getHighPriorityEntityIds());54+public function testGetEntityListGroups(): void21-$this->assertSame($normal, $selectionList->getNormalPriorityEntityId());55+ {56+$selectionList = new SelectionList();57+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);58+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2]);225923-$this->assertSame(['p1', 'p2', 'n1', 'n2'], $selectionList->getAllIds());60+$this->assertSame(['high', 'normal'], $selectionList->getEntityListGroups());24 }61 }256226public function testCountReturnsTotalCount(): void63public function testCountReturnsTotalCount(): void27 {64 {28-$selectionList = new SelectionList(['p1'], ['n1', 'n2']);65+$selectionList = new SelectionList();66+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);67+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2, 3]);68+29$this->assertSame(3, $selectionList->count());69$this->assertSame(3, $selectionList->count());30 }70 }317132-public function testIsEmptyReturnsTrueWhenBothListsAreEmpty(): void72+public function testIsEmptyReturnsTrueWhenNoEntitiesAdded(): void33 {73 {34-$selectionList = new SelectionList([], []);74+$selectionList = new SelectionList();75+35$this->assertTrue($selectionList->isEmpty());76$this->assertTrue($selectionList->isEmpty());36 }77 }377838-public function testIsEmptyReturnsFalseWhenAnyListIsNotEmpty(): void79+public function testIsEmptyReturnsFalseWhenEntitiesAdded(): void39 {80 {40-$selectionList = new SelectionList(['p1'], []);81+$selectionList = new SelectionList();41-$this->assertFalse($selectionList->isEmpty());82+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);428343-$selectionList2 = new SelectionList([], ['n1']);84+$this->assertFalse($selectionList->isEmpty());44-$this->assertFalse($selectionList2->isEmpty());45 }85 }468647-public function testIsStaleChunkSelected(): void87+public function testMarkStaleAndIsStaleChunkSelected(): void48 {88 {49-$selectionList = new SelectionList([], [], true);89+$selectionList = new SelectionList();50-$this->assertTrue($selectionList->isStaleChunkSelected());90+91+$this->assertFalse($selectionList->isStaleChunkSelected());92+93+$selectionList->markStale();519452-$selectionList2 = new SelectionList([], [], false);95+$this->assertTrue($selectionList->isStaleChunkSelected());53-$this->assertFalse($selectionList2->isStaleChunkSelected());54 }96 }559756public function testIsFullChunk(): void98public function testIsFullChunk(): void57 {99 {58-$chunkSize = 200;100+$selectionList = new SelectionList();59-101+$selectionList->setChunkSize(self::CHUNK_SIZE);60-$fullList = range(1, $chunkSize);102+61-$selectionList = new SelectionList(103+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, self::CHUNK_SIZE));62- priorityEntityIdList: $fullList,104+63- normalEntityIdList: [],105+$this->assertTrue($selectionList->isFullChunk());64- chunkSize: $chunkSize,106+ }65- );107+108+public function testIsNotFullChunkWhenBelowChunkSize(): void109+ {110+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);111+112+$selectionList = new SelectionList();113+$selectionList->setChunkSize(self::CHUNK_SIZE);114+115+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range(1, $halfRange));116+117+$this->assertFalse($selectionList->isFullChunk());118+ }119+120+public function testIsFullChunkAcrossMultiplePriorityGroups(): void121+ {122+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);123+124+$selectionList = new SelectionList();125+$selectionList->setChunkSize(self::CHUNK_SIZE);126+127+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, $halfRange));128+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range($halfRange + 1, self::CHUNK_SIZE));129+130+$this->assertTrue($selectionList->isFullChunk());131+ }132+133+public function testSetChunkSizeAffectsIsFullChunk(): void134+ {135+$selectionList = new SelectionList();136+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [1, 2, 3]);137+138+$selectionList->setChunkSize(3);66$this->assertTrue($selectionList->isFullChunk());139$this->assertTrue($selectionList->isFullChunk());6714068-$halfRange = (int) ceil($chunkSize / 2);141+$selectionList->setChunkSize(50);69-142+$this->assertFalse($selectionList->isFullChunk());70-$notFullList = range(1, $halfRange);71-$selectionList2 = new SelectionList(72- priorityEntityIdList: $notFullList,73- normalEntityIdList: [],74- chunkSize: $chunkSize,75- );76-$this->assertFalse($selectionList2->isFullChunk());77-78-$priorityRange = range(1, $halfRange);79-$normalRange = range($halfRange + 1, $chunkSize);80-81-$selectionList3 = new SelectionList(82- priorityEntityIdList: $priorityRange,83- normalEntityIdList: $normalRange,84- chunkSize: $chunkSize,85- );86-$this->assertTrue($selectionList3->isFullChunk());87 }143 }88}144}</selection>” selected.","depth":23,"bounds":{"left":0.20578457,"top":0.19473264,"width":0.13696809,"height":0.80526733},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.","depth":23,"bounds":{"left":0.20578457,"top":0.30965683,"width":0.13248006,"height":0.073822826},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Expand","depth":21,"bounds":{"left":0.34275267,"top":0.19313647,"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":"Listen","depth":22,"bounds":{"left":0.3480718,"top":0.32083002,"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.32322428,"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.36472467,"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.36671987,"width":0.04105718,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Here is a summary of the changes made to the","depth":24,"bounds":{"left":0.11336436,"top":0.36871508,"width":0.11419548,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SelectionListTest","depth":25,"bounds":{"left":0.22955452,"top":0.3699122,"width":0.047539894,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"file, reflecting a significant refactoring of how the","depth":24,"bounds":{"left":0.11336436,"top":0.36871508,"width":0.23204787,"height":0.038707104},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SelectionList","depth":25,"bounds":{"left":0.1705452,"top":0.39225858,"width":0.036402926,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"class manages state and priorities.","depth":24,"bounds":{"left":0.20894282,"top":0.39106146,"width":0.08494016,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Object Instantiation and State Management","depth":23,"bounds":{"left":0.11336436,"top":0.43256184,"width":0.24534574,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Object Instantiation and State Management","depth":24,"bounds":{"left":0.11336436,"top":0.43415803,"width":0.11319814,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Removed Constructor Injection:","depth":26,"bounds":{"left":0.12599733,"top":0.4612929,"width":0.082446806,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The tests no longer pass arrays, chunk sizes, or boolean flags directly into the","depth":26,"bounds":{"left":0.12599733,"top":0.4612929,"width":0.23271276,"height":0.038707104},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SelectionList","depth":27,"bounds":{"left":0.16722074,"top":0.4848364,"width":0.036236703,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"constructor. Objects are now instantiated empty (","depth":26,"bounds":{"left":0.20545213,"top":0.48363927,"width":0.12084442,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"new SelectionList()","depth":27,"bounds":{"left":0.12599733,"top":0.4848364,"width":0.21343085,"height":0.037110932},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":").","depth":26,"bounds":{"left":0.16988032,"top":0.5059856,"width":0.0033244682,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Introduced","depth":26,"bounds":{"left":0.12599733,"top":0.5371109,"width":0.029920213,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"addEntityList()","depth":27,"bounds":{"left":0.15791224,"top":0.5383081,"width":0.041888297,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":":","depth":26,"bounds":{"left":0.2017952,"top":0.5371109,"width":0.0014960107,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Added tests for populating the selection list dynamically using","depth":26,"bounds":{"left":0.20329122,"top":0.5371109,"width":0.15226063,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"addEntityList()","depth":27,"bounds":{"left":0.12799202,"top":0.5606544,"width":0.041888297,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":", which pairs a","depth":26,"bounds":{"left":0.171875,"top":0.5594573,"width":0.035738032,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"QueuePriorityEnum","depth":27,"bounds":{"left":0.2096077,"top":0.5606544,"width":0.047539894,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(e.g.,","depth":26,"bounds":{"left":0.25914228,"top":0.5594573,"width":0.014793883,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"HIGH","depth":27,"bounds":{"left":0.27593085,"top":0.5606544,"width":0.011303191,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":26,"bounds":{"left":0.28922874,"top":0.5594573,"width":0.0026595744,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"NORMAL","depth":27,"bounds":{"left":0.29388297,"top":0.5606544,"width":0.016788565,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":26,"bounds":{"left":0.31266624,"top":0.5594573,"width":0.0026595744,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"LOW","depth":27,"bounds":{"left":0.31732047,"top":0.5606544,"width":0.008477394,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":") with an array of IDs.","depth":26,"bounds":{"left":0.12599733,"top":0.5594573,"width":0.2237367,"height":0.038707104},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Merged Priorities:","depth":26,"bounds":{"left":0.12599733,"top":0.612929,"width":0.04637633,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Added tests confirming that invoking","depth":26,"bounds":{"left":0.17237367,"top":0.612929,"width":0.09125665,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"addEntityList()","depth":27,"bounds":{"left":0.265625,"top":0.6141261,"width":0.041888297,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"multiple times for the same priority group successfully merges the ID arrays.","depth":26,"bounds":{"left":0.12599733,"top":0.612929,"width":0.22822474,"height":0.038707104},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Updated Data Retrieval","depth":23,"bounds":{"left":0.11336436,"top":0.67677575,"width":0.24534574,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Updated Data Retrieval","depth":24,"bounds":{"left":0.11336436,"top":0.6783719,"width":0.06067154,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Generic Group Getters:","depth":26,"bounds":{"left":0.12599733,"top":0.7055068,"width":0.06017287,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Removed legacy priority-specific getters (e.g.,","depth":26,"bounds":{"left":0.1861702,"top":0.7055068,"width":0.114527926,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"getHighPriorityEntityIds()","depth":27,"bounds":{"left":0.12799202,"top":0.7290503,"width":0.07263963,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"). These are replaced by tests for","depth":26,"bounds":{"left":0.20262633,"top":0.7278532,"width":0.080784574,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"getEntityListItemsByGroup()","depth":27,"bounds":{"left":0.12799202,"top":0.75139666,"width":0.075465426,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":", which fetches IDs based on the provided enum.","depth":26,"bounds":{"left":0.20545213,"top":0.7501995,"width":0.1171875,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Unknown Group Handling:","depth":26,"bounds":{"left":0.12599733,"top":0.7813248,"width":0.0674867,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Added validation that","depth":26,"bounds":{"left":0.19348404,"top":0.7813248,"width":0.05418883,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"getEntityListItemsByGroup()","depth":27,"bounds":{"left":0.24966756,"top":0.78252196,"width":0.075465426,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"safely returns an empty array when querying an unpopulated priority group.","depth":26,"bounds":{"left":0.12599733,"top":0.7813248,"width":0.21808511,"height":0.038707104},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Group Listing:","depth":26,"bounds":{"left":0.12599733,"top":0.8347965,"width":0.03656915,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Added","depth":26,"bounds":{"left":0.16256648,"top":0.8347965,"width":0.018450798,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"testGetEntityListGroups()","depth":27,"bounds":{"left":0.18301196,"top":0.8359936,"width":0.06981383,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"to verify the retrieval of all active priority group keys (e.g.,","depth":26,"bounds":{"left":0.12599733,"top":0.8347965,"width":0.2293883,"height":0.038707104},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"['high', 'normal']","depth":27,"bounds":{"left":0.16938165,"top":0.85833997,"width":0.050199468,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":").","depth":26,"bounds":{"left":0.2215758,"top":0.85714287,"width":0.0033244682,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Aggregated Fetching:","depth":26,"bounds":{"left":0.12599733,"top":0.8882682,"width":0.055851065,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Maintained and updated tests for","depth":26,"bounds":{"left":0.1818484,"top":0.8882682,"width":0.08294548,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"getAllIds()","depth":27,"bounds":{"left":0.26678857,"top":0.8894653,"width":0.030751329,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"to ensure it correctly flattens IDs across all newly structured priority groups.","depth":26,"bounds":{"left":0.12599733,"top":0.8882682,"width":0.22623006,"height":0.038707104},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Chunking and Flags","depth":23,"bounds":{"left":0.11336436,"top":0.95211494,"width":0.24534574,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Chunking and Flags","depth":24,"bounds":{"left":0.11336436,"top":0.9537111,"width":0.051030584,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Dynamic Chunk Sizing:","depth":26,"bounds":{"left":0.12599733,"top":0.980846,"width":0.059175532,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Introduced a","depth":26,"bounds":{"left":0.18517287,"top":0.980846,"width":0.033410903,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"CHUNK_SIZE","depth":27,"bounds":{"left":0.22057846,"top":0.9820431,"width":0.027925532,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"constant and replaced constructor-based chunk sizing with a new","depth":26,"bounds":{"left":0.12599733,"top":0.980846,"width":0.22839096,"height":0.019154012},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"setChunkSize()","depth":27,"bounds":{"left":0.1861702,"top":1.0,"width":0.0390625,"height":-0.0043895245},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"method.","depth":26,"bounds":{"left":0.22722739,"top":1.0,"width":0.02144282,"height":-0.0031923056},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Chunk Validation:","depth":26,"bounds":{"left":0.12599733,"top":1.0,"width":0.045545213,"height":-0.034317613},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Expanded","depth":26,"bounds":{"left":0.17154256,"top":1.0,"width":0.026928192,"height":-0.034317613},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"isFullChunk()","depth":27,"bounds":{"left":0.20046543,"top":1.0,"width":0.036236703,"height":-0.035514712},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"tests to verify behavior when exactly at chunk capacity, below capacity, when capacities are split across multiple priority groups, and when the chunk size is changed dynamically.","depth":26,"bounds":{"left":0.12599733,"top":1.0,"width":0.23271276,"height":-0.034317613},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Stale Status:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Replaced the constructor-injected stale flag with a new","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"markStale()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"method, testing that","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"isStaleChunkSelected()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"correctly toggles from false to true.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Utility Methods:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Updated tests for","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"count()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"and","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"isEmpty()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"to align with the new","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"addEntityList","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"structure rather than constructor arrays.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Good response","depth":21,"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":21,"on_screen":false,"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":false,"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":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy","depth":21,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Show more options","depth":20,"on_screen":false,"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":true,"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,"bounds":{"left":0.40541887,"top":0.0,"width":0.011469414,"height":0.013567438},"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,"bounds":{"left":0.43301198,"top":0.0,"width":0.02925532,"height":0.013567438},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":14,"bounds":{"left":0.46492687,"top":0.0,"width":0.0029920214,"height":0.013567438},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"31","depth":14,"bounds":{"left":0.46791887,"top":0.0,"width":0.004986702,"height":0.013567438},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")","depth":14,"bounds":{"left":0.47290558,"top":0.0,"width":0.0016622341,"height":0.013567438},"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,"bounds":{"left":0.49052528,"top":0.0,"width":0.014960106,"height":0.013567438},"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,"bounds":{"left":0.52244014,"top":0.0,"width":0.015957447,"height":0.013567438},"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,"bounds":{"left":0.55502,"top":0.0,"width":0.009142287,"height":0.013567438},"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,"bounds":{"left":0.5816157,"top":0.0,"width":0.04255319,"height":0.013567438},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":14,"bounds":{"left":0.62799203,"top":0.0,"width":0.0029920214,"height":0.013567438},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1","depth":14,"bounds":{"left":0.63098407,"top":0.0,"width":0.0019946808,"height":0.013567438},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")","depth":14,"bounds":{"left":0.63297874,"top":0.0,"width":0.0018284575,"height":0.013567438},"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,"bounds":{"left":0.65109706,"top":0.0,"width":0.016788565,"height":0.013567438},"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,"bounds":{"left":0.68484044,"top":0.0,"width":0.017785905,"height":0.013567438},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Important update","depth":10,"bounds":{"left":0.40292552,"top":0.0,"width":0.0003324468,"height":0.016759777},"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Important update","depth":11,"bounds":{"left":0.40292552,"top":0.0,"width":0.039228722,"height":0.013567438},"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,"bounds":{"left":0.40292552,"top":0.0,"width":0.2159242,"height":0.013567438},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review this update","depth":10,"bounds":{"left":0.61884975,"top":0.0,"width":0.04055851,"height":0.013567438},"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,"bounds":{"left":0.61884975,"top":0.0,"width":0.04055851,"height":0.013567438},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"and manage your preferences in your","depth":10,"bounds":{"left":0.6594083,"top":0.0,"width":0.08261303,"height":0.013567438},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"GitHub account settings","depth":10,"bounds":{"left":0.74202126,"top":0.0,"width":0.05219415,"height":0.013567438},"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,"bounds":{"left":0.74202126,"top":0.0,"width":0.05219415,"height":0.013567438},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":".","depth":10,"bounds":{"left":0.79421544,"top":0.0,"width":0.0013297872,"height":0.013567438},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Dismiss banner","depth":9,"bounds":{"left":0.9865359,"top":0.0,"width":0.010638298,"height":0.025538707},"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,"bounds":{"left":0.39993352,"top":0.0,"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.0,"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.0,"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.0,"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.0,"width":0.010638298,"height":0.025538707},"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,"bounds":{"left":0.9584442,"top":0.0,"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.0035913808,"width":0.01512633,"height":0.011971269},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Awaiting approval","depth":13,"bounds":{"left":0.86818486,"top":0.0,"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.0031923384,"width":0.03873005,"height":0.013567438},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Code","depth":13,"bounds":{"left":0.9261968,"top":0.0,"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.0031923384,"width":0.011635638,"height":0.013567438},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Open","depth":13,"bounds":{"left":0.4105718,"top":0.035115723,"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.031923383,"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.033519555,"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.033519555,"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.03152434,"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.03471668,"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.033519555,"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.03152434,"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.03471668,"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.029130088,"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.08539505,"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.06743815,"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.07701516,"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.07701516,"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.07701516,"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.07701516,"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.06743815,"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.07701516,"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.07701516,"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.07701516,"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.07701516,"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.06743815,"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.07701516,"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.07701516,"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.07701516,"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.07701516,"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.06743815,"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.07701516,"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.07701516,"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.07701516,"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.07701516,"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.122505985,"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.12529927,"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.11173184,"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.11173184,"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.11691939,"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.12410215,"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.11173184,"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.11691939,"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.11691939,"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.11173184,"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.11173184,"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.11173184,"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.11691939,"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.11691939,"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.11691939,"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.16081405,"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.16001596,"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.19832402,"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.20111732,"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.20430966,"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.23024741,"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.25578612,"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.28132483,"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.28132483,"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.30686352,"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}]...
|
6164317061280969025
|
3554570533066268053
|
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
Copy prompt
Edit
You said I’m on page “<tabTitle>JY-20808 low priority indexing queue by Vasil-Jimi</tabTitle>” with “<selection>@@ -5,84 +5,140 @@5namespace Tests\Unit\Component\ES\Processor\DTOs;5namespace Tests\Unit\Component\ES\Processor\DTOs;667use Jiminny\Component\ES\Processor\DTOs\SelectionList;7use Jiminny\Component\ES\Processor\DTOs\SelectionList;8+use Jiminny\Component\ES\QueuePriorityEnum;8use PHPUnit\Framework\Attributes\CoversClass;9use PHPUnit\Framework\Attributes\CoversClass;9use PHPUnit\Framework\TestCase;10use PHPUnit\Framework\TestCase;101111#[CoversClass(SelectionList::class)]12#[CoversClass(SelectionList::class)]12final class SelectionListTest extends TestCase13final class SelectionListTest extends TestCase13{14{14-public function testGetEntityIds(): void15+private const int CHUNK_SIZE = 100;16+17+public function testAddEntityListAndGetAllIds(): void18+ {19+$selectionList = new SelectionList();20+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);21+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);22+23+$this->assertSame([1, 2, 3, 4], $selectionList->getAllIds());24+ }25+26+public function testAddEntityListMergesMultipleCallsForSamePriority(): void27+ {28+$selectionList = new SelectionList();29+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);30+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [3, 4]);31+32+$this->assertSame([1, 2, 3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));33+ }34+35+public function testGetEntityListItemsByGroup(): void36+ {37+$selectionList = new SelectionList();38+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);39+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);40+$selectionList->addEntityList(QueuePriorityEnum::LOW, [5, 6]);41+42+$this->assertSame([1, 2], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));43+$this->assertSame([3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::NORMAL));44+$this->assertSame([5, 6], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::LOW));45+ }46+47+public function testGetEntityListItemsByGroupReturnsEmptyArrayForUnknownGroup(): void15 {48 {16-$priority = ['p1', 'p2'];49+$selectionList = new SelectionList();17-$normal = ['n1', 'n2'];50+18-$selectionList = new SelectionList($priority, $normal);51+$this->assertSame([], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));52+ }195320-$this->assertSame($priority, $selectionList->getHighPriorityEntityIds());54+public function testGetEntityListGroups(): void21-$this->assertSame($normal, $selectionList->getNormalPriorityEntityId());55+ {56+$selectionList = new SelectionList();57+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);58+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2]);225923-$this->assertSame(['p1', 'p2', 'n1', 'n2'], $selectionList->getAllIds());60+$this->assertSame(['high', 'normal'], $selectionList->getEntityListGroups());24 }61 }256226public function testCountReturnsTotalCount(): void63public function testCountReturnsTotalCount(): void27 {64 {28-$selectionList = new SelectionList(['p1'], ['n1', 'n2']);65+$selectionList = new SelectionList();66+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);67+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2, 3]);68+29$this->assertSame(3, $selectionList->count());69$this->assertSame(3, $selectionList->count());30 }70 }317132-public function testIsEmptyReturnsTrueWhenBothListsAreEmpty(): void72+public function testIsEmptyReturnsTrueWhenNoEntitiesAdded(): void33 {73 {34-$selectionList = new SelectionList([], []);74+$selectionList = new SelectionList();75+35$this->assertTrue($selectionList->isEmpty());76$this->assertTrue($selectionList->isEmpty());36 }77 }377838-public function testIsEmptyReturnsFalseWhenAnyListIsNotEmpty(): void79+public function testIsEmptyReturnsFalseWhenEntitiesAdded(): void39 {80 {40-$selectionList = new SelectionList(['p1'], []);81+$selectionList = new SelectionList();41-$this->assertFalse($selectionList->isEmpty());82+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);428343-$selectionList2 = new SelectionList([], ['n1']);84+$this->assertFalse($selectionList->isEmpty());44-$this->assertFalse($selectionList2->isEmpty());45 }85 }468647-public function testIsStaleChunkSelected(): void87+public function testMarkStaleAndIsStaleChunkSelected(): void48 {88 {49-$selectionList = new SelectionList([], [], true);89+$selectionList = new SelectionList();50-$this->assertTrue($selectionList->isStaleChunkSelected());90+91+$this->assertFalse($selectionList->isStaleChunkSelected());92+93+$selectionList->markStale();519452-$selectionList2 = new SelectionList([], [], false);95+$this->assertTrue($selectionList->isStaleChunkSelected());53-$this->assertFalse($selectionList2->isStaleChunkSelected());54 }96 }559756public function testIsFullChunk(): void98public function testIsFullChunk(): void57 {99 {58-$chunkSize = 200;100+$selectionList = new SelectionList();59-101+$selectionList->setChunkSize(self::CHUNK_SIZE);60-$fullList = range(1, $chunkSize);102+61-$selectionList = new SelectionList(103+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, self::CHUNK_SIZE));62- priorityEntityIdList: $fullList,104+63- normalEntityIdList: [],105+$this->assertTrue($selectionList->isFullChunk());64- chunkSize: $chunkSize,106+ }65- );107+108+public function testIsNotFullChunkWhenBelowChunkSize(): void109+ {110+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);111+112+$selectionList = new SelectionList();113+$selectionList->setChunkSize(self::CHUNK_SIZE);114+115+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range(1, $halfRange));116+117+$this->assertFalse($selectionList->isFullChunk());118+ }119+120+public function testIsFullChunkAcrossMultiplePriorityGroups(): void121+ {122+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);123+124+$selectionList = new SelectionList();125+$selectionList->setChunkSize(self::CHUNK_SIZE);126+127+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, $halfRange));128+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range($halfRange + 1, self::CHUNK_SIZE));129+130+$this->assertTrue($selectionList->isFullChunk());131+ }132+133+public function testSetChunkSizeAffectsIsFullChunk(): void134+ {135+$selectionList = new SelectionList();136+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [1, 2, 3]);137+138+$selectionList->setChunkSize(3);66$this->assertTrue($selectionList->isFullChunk());139$this->assertTrue($selectionList->isFullChunk());6714068-$halfRange = (int) ceil($chunkSize / 2);141+$selectionList->setChunkSize(50);69-142+$this->assertFalse($selectionList->isFullChunk());70-$notFullList = range(1, $halfRange);71-$selectionList2 = new SelectionList(72- priorityEntityIdList: $notFullList,73- normalEntityIdList: [],74- chunkSize: $chunkSize,75- );76-$this->assertFalse($selectionList2->isFullChunk());77-78-$priorityRange = range(1, $halfRange);79-$normalRange = range($halfRange + 1, $chunkSize);80-81-$selectionList3 = new SelectionList(82- priorityEntityIdList: $priorityRange,83- normalEntityIdList: $normalRange,84- chunkSize: $chunkSize,85- );86-$this->assertTrue($selectionList3->isFullChunk());87 }143 }88}144}</selection>” selected. Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
You said
I’m on page “<tabTitle>JY-20808 low priority indexing queue by Vasil-Jimi</tabTitle>” with “<selection>@@ -5,84 +5,140 @@5namespace Tests\Unit\Component\ES\Processor\DTOs;5namespace Tests\Unit\Component\ES\Processor\DTOs;667use Jiminny\Component\ES\Processor\DTOs\SelectionList;7use Jiminny\Component\ES\Processor\DTOs\SelectionList;8+use Jiminny\Component\ES\QueuePriorityEnum;8use PHPUnit\Framework\Attributes\CoversClass;9use PHPUnit\Framework\Attributes\CoversClass;9use PHPUnit\Framework\TestCase;10use PHPUnit\Framework\TestCase;101111#[CoversClass(SelectionList::class)]12#[CoversClass(SelectionList::class)]12final class SelectionListTest extends TestCase13final class SelectionListTest extends TestCase13{14{14-public function testGetEntityIds(): void15+private const int CHUNK_SIZE = 100;16+17+public function testAddEntityListAndGetAllIds(): void18+ {19+$selectionList = new SelectionList();20+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);21+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);22+23+$this->assertSame([1, 2, 3, 4], $selectionList->getAllIds());24+ }25+26+public function testAddEntityListMergesMultipleCallsForSamePriority(): void27+ {28+$selectionList = new SelectionList();29+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);30+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [3, 4]);31+32+$this->assertSame([1, 2, 3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));33+ }34+35+public function testGetEntityListItemsByGroup(): void36+ {37+$selectionList = new SelectionList();38+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);39+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);40+$selectionList->addEntityList(QueuePriorityEnum::LOW, [5, 6]);41+42+$this->assertSame([1, 2], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));43+$this->assertSame([3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::NORMAL));44+$this->assertSame([5, 6], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::LOW));45+ }46+47+public function testGetEntityListItemsByGroupReturnsEmptyArrayForUnknownGroup(): void15 {48 {16-$priority = ['p1', 'p2'];49+$selectionList = new SelectionList();17-$normal = ['n1', 'n2'];50+18-$selectionList = new SelectionList($priority, $normal);51+$this->assertSame([], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));52+ }195320-$this->assertSame($priority, $selectionList->getHighPriorityEntityIds());54+public function testGetEntityListGroups(): void21-$this->assertSame($normal, $selectionList->getNormalPriorityEntityId());55+ {56+$selectionList = new SelectionList();57+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);58+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2]);225923-$this->assertSame(['p1', 'p2', 'n1', 'n2'], $selectionList->getAllIds());60+$this->assertSame(['high', 'normal'], $selectionList->getEntityListGroups());24 }61 }256226public function testCountReturnsTotalCount(): void63public function testCountReturnsTotalCount(): void27 {64 {28-$selectionList = new SelectionList(['p1'], ['n1', 'n2']);65+$selectionList = new SelectionList();66+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);67+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2, 3]);68+29$this->assertSame(3, $selectionList->count());69$this->assertSame(3, $selectionList->count());30 }70 }317132-public function testIsEmptyReturnsTrueWhenBothListsAreEmpty(): void72+public function testIsEmptyReturnsTrueWhenNoEntitiesAdded(): void33 {73 {34-$selectionList = new SelectionList([], []);74+$selectionList = new SelectionList();75+35$this->assertTrue($selectionList->isEmpty());76$this->assertTrue($selectionList->isEmpty());36 }77 }377838-public function testIsEmptyReturnsFalseWhenAnyListIsNotEmpty(): void79+public function testIsEmptyReturnsFalseWhenEntitiesAdded(): void39 {80 {40-$selectionList = new SelectionList(['p1'], []);81+$selectionList = new SelectionList();41-$this->assertFalse($selectionList->isEmpty());82+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);428343-$selectionList2 = new SelectionList([], ['n1']);84+$this->assertFalse($selectionList->isEmpty());44-$this->assertFalse($selectionList2->isEmpty());45 }85 }468647-public function testIsStaleChunkSelected(): void87+public function testMarkStaleAndIsStaleChunkSelected(): void48 {88 {49-$selectionList = new SelectionList([], [], true);89+$selectionList = new SelectionList();50-$this->assertTrue($selectionList->isStaleChunkSelected());90+91+$this->assertFalse($selectionList->isStaleChunkSelected());92+93+$selectionList->markStale();519452-$selectionList2 = new SelectionList([], [], false);95+$this->assertTrue($selectionList->isStaleChunkSelected());53-$this->assertFalse($selectionList2->isStaleChunkSelected());54 }96 }559756public function testIsFullChunk(): void98public function testIsFullChunk(): void57 {99 {58-$chunkSize = 200;100+$selectionList = new SelectionList();59-101+$selectionList->setChunkSize(self::CHUNK_SIZE);60-$fullList = range(1, $chunkSize);102+61-$selectionList = new SelectionList(103+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, self::CHUNK_SIZE));62- priorityEntityIdList: $fullList,104+63- normalEntityIdList: [],105+$this->assertTrue($selectionList->isFullChunk());64- chunkSize: $chunkSize,106+ }65- );107+108+public function testIsNotFullChunkWhenBelowChunkSize(): void109+ {110+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);111+112+$selectionList = new SelectionList();113+$selectionList->setChunkSize(self::CHUNK_SIZE);114+115+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range(1, $halfRange));116+117+$this->assertFalse($selectionList->isFullChunk());118+ }119+120+public function testIsFullChunkAcrossMultiplePriorityGroups(): void121+ {122+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);123+124+$selectionList = new SelectionList();125+$selectionList->setChunkSize(self::CHUNK_SIZE);126+127+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, $halfRange));128+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range($halfRange + 1, self::CHUNK_SIZE));129+130+$this->assertTrue($selectionList->isFullChunk());131+ }132+133+public function testSetChunkSizeAffectsIsFullChunk(): void134+ {135+$selectionList = new SelectionList();136+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [1, 2, 3]);137+138+$selectionList->setChunkSize(3);66$this->assertTrue($selectionList->isFullChunk());139$this->assertTrue($selectionList->isFullChunk());6714068-$halfRange = (int) ceil($chunkSize / 2);141+$selectionList->setChunkSize(50);69-142+$this->assertFalse($selectionList->isFullChunk());70-$notFullList = range(1, $halfRange);71-$selectionList2 = new SelectionList(72- priorityEntityIdList: $notFullList,73- normalEntityIdList: [],74- chunkSize: $chunkSize,75- );76-$this->assertFalse($selectionList2->isFullChunk());77-78-$priorityRange = range(1, $halfRange);79-$normalRange = range($halfRange + 1, $chunkSize);80-81-$selectionList3 = new SelectionList(82- priorityEntityIdList: $priorityRange,83- normalEntityIdList: $normalRange,84- chunkSize: $chunkSize,85- );86-$this->assertTrue($selectionList3->isFullChunk());87 }143 }88}144}</selection>” selected.
Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
Expand
Listen
Show thinking
Gemini said
Gemini said
Here is a summary of the changes made to the
SelectionListTest
file, reflecting a significant refactoring of how the
SelectionList
class manages state and priorities.
Object Instantiation and State Management
Object Instantiation and State Management
Removed Constructor Injection:
The tests no longer pass arrays, chunk sizes, or boolean flags directly into the
SelectionList
constructor. Objects are now instantiated empty (
new SelectionList()
).
Introduced
addEntityList()
:
Added tests for populating the selection list dynamically using
addEntityList()
, which pairs a
QueuePriorityEnum
(e.g.,
HIGH
,
NORMAL
,
LOW
) with an array of IDs.
Merged Priorities:
Added tests confirming that invoking
addEntityList()
multiple times for the same priority group successfully merges the ID arrays.
Updated Data Retrieval
Updated Data Retrieval
Generic Group Getters:
Removed legacy priority-specific getters (e.g.,
getHighPriorityEntityIds()
). These are replaced by tests for
getEntityListItemsByGroup()
, which fetches IDs based on the provided enum.
Unknown Group Handling:
Added validation that
getEntityListItemsByGroup()
safely returns an empty array when querying an unpopulated priority group.
Group Listing:
Added
testGetEntityListGroups()
to verify the retrieval of all active priority group keys (e.g.,
['high', 'normal']
).
Aggregated Fetching:
Maintained and updated tests for
getAllIds()
to ensure it correctly flattens IDs across all newly structured priority groups.
Chunking and Flags
Chunking and Flags
Dynamic Chunk Sizing:
Introduced a
CHUNK_SIZE
constant and replaced constructor-based chunk sizing with a new
setChunkSize()
method.
Chunk Validation:
Expanded
isFullChunk()
tests to verify behavior when exactly at chunk capacity, below capacity, when capacities are split across multiple priority groups, and when the chunk size is changed dynamically.
Stale Status:
Replaced the constructor-injected stale flag with a new
markStale()
method, testing that
isStaleChunkSelected()
correctly toggles from false to true.
Utility Methods:
Updated tests for
count()
and
isEmpty()
to align with the new
addEntityList
structure rather than constructor arrays.
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...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
55663
|
1932
|
1
|
2026-05-19T06:37:30.371980+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779172650371_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
Copy prompt
Edit
You said I’m on page “<tabTitle>JY-20808 low priority indexing queue by Vasil-Jimi</tabTitle>” with “<selection>@@ -5,84 +5,140 @@5namespace Tests\Unit\Component\ES\Processor\DTOs;5namespace Tests\Unit\Component\ES\Processor\DTOs;667use Jiminny\Component\ES\Processor\DTOs\SelectionList;7use Jiminny\Component\ES\Processor\DTOs\SelectionList;8+use Jiminny\Component\ES\QueuePriorityEnum;8use PHPUnit\Framework\Attributes\CoversClass;9use PHPUnit\Framework\Attributes\CoversClass;9use PHPUnit\Framework\TestCase;10use PHPUnit\Framework\TestCase;101111#[CoversClass(SelectionList::class)]12#[CoversClass(SelectionList::class)]12final class SelectionListTest extends TestCase13final class SelectionListTest extends TestCase13{14{14-public function testGetEntityIds(): void15+private const int CHUNK_SIZE = 100;16+17+public function testAddEntityListAndGetAllIds(): void18+ {19+$selectionList = new SelectionList();20+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);21+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);22+23+$this->assertSame([1, 2, 3, 4], $selectionList->getAllIds());24+ }25+26+public function testAddEntityListMergesMultipleCallsForSamePriority(): void27+ {28+$selectionList = new SelectionList();29+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);30+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [3, 4]);31+32+$this->assertSame([1, 2, 3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));33+ }34+35+public function testGetEntityListItemsByGroup(): void36+ {37+$selectionList = new SelectionList();38+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);39+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);40+$selectionList->addEntityList(QueuePriorityEnum::LOW, [5, 6]);41+42+$this->assertSame([1, 2], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));43+$this->assertSame([3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::NORMAL));44+$this->assertSame([5, 6], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::LOW));45+ }46+47+public function testGetEntityListItemsByGroupReturnsEmptyArrayForUnknownGroup(): void15 {48 {16-$priority = ['p1', 'p2'];49+$selectionList = new SelectionList();17-$normal = ['n1', 'n2'];50+18-$selectionList = new SelectionList($priority, $normal);51+$this->assertSame([], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));52+ }195320-$this->assertSame($priority, $selectionList->getHighPriorityEntityIds());54+public function testGetEntityListGroups(): void21-$this->assertSame($normal, $selectionList->getNormalPriorityEntityId());55+ {56+$selectionList = new SelectionList();57+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);58+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2]);225923-$this->assertSame(['p1', 'p2', 'n1', 'n2'], $selectionList->getAllIds());60+$this->assertSame(['high', 'normal'], $selectionList->getEntityListGroups());24 }61 }256226public function testCountReturnsTotalCount(): void63public function testCountReturnsTotalCount(): void27 {64 {28-$selectionList = new SelectionList(['p1'], ['n1', 'n2']);65+$selectionList = new SelectionList();66+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);67+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2, 3]);68+29$this->assertSame(3, $selectionList->count());69$this->assertSame(3, $selectionList->count());30 }70 }317132-public function testIsEmptyReturnsTrueWhenBothListsAreEmpty(): void72+public function testIsEmptyReturnsTrueWhenNoEntitiesAdded(): void33 {73 {34-$selectionList = new SelectionList([], []);74+$selectionList = new SelectionList();75+35$this->assertTrue($selectionList->isEmpty());76$this->assertTrue($selectionList->isEmpty());36 }77 }377838-public function testIsEmptyReturnsFalseWhenAnyListIsNotEmpty(): void79+public function testIsEmptyReturnsFalseWhenEntitiesAdded(): void39 {80 {40-$selectionList = new SelectionList(['p1'], []);81+$selectionList = new SelectionList();41-$this->assertFalse($selectionList->isEmpty());82+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);428343-$selectionList2 = new SelectionList([], ['n1']);84+$this->assertFalse($selectionList->isEmpty());44-$this->assertFalse($selectionList2->isEmpty());45 }85 }468647-public function testIsStaleChunkSelected(): void87+public function testMarkStaleAndIsStaleChunkSelected(): void48 {88 {49-$selectionList = new SelectionList([], [], true);89+$selectionList = new SelectionList();50-$this->assertTrue($selectionList->isStaleChunkSelected());90+91+$this->assertFalse($selectionList->isStaleChunkSelected());92+93+$selectionList->markStale();519452-$selectionList2 = new SelectionList([], [], false);95+$this->assertTrue($selectionList->isStaleChunkSelected());53-$this->assertFalse($selectionList2->isStaleChunkSelected());54 }96 }559756public function testIsFullChunk(): void98public function testIsFullChunk(): void57 {99 {58-$chunkSize = 200;100+$selectionList = new SelectionList();59-101+$selectionList->setChunkSize(self::CHUNK_SIZE);60-$fullList = range(1, $chunkSize);102+61-$selectionList = new SelectionList(103+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, self::CHUNK_SIZE));62- priorityEntityIdList: $fullList,104+63- normalEntityIdList: [],105+$this->assertTrue($selectionList->isFullChunk());64- chunkSize: $chunkSize,106+ }65- );107+108+public function testIsNotFullChunkWhenBelowChunkSize(): void109+ {110+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);111+112+$selectionList = new SelectionList();113+$selectionList->setChunkSize(self::CHUNK_SIZE);114+115+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range(1, $halfRange));116+117+$this->assertFalse($selectionList->isFullChunk());118+ }119+120+public function testIsFullChunkAcrossMultiplePriorityGroups(): void121+ {122+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);123+124+$selectionList = new SelectionList();125+$selectionList->setChunkSize(self::CHUNK_SIZE);126+127+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, $halfRange));128+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range($halfRange + 1, self::CHUNK_SIZE));129+130+$this->assertTrue($selectionList->isFullChunk());131+ }132+133+public function testSetChunkSizeAffectsIsFullChunk(): void134+ {135+$selectionList = new SelectionList();136+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [1, 2, 3]);137+138+$selectionList->setChunkSize(3);66$this->assertTrue($selectionList->isFullChunk());139$this->assertTrue($selectionList->isFullChunk());6714068-$halfRange = (int) ceil($chunkSize / 2);141+$selectionList->setChunkSize(50);69-142+$this->assertFalse($selectionList->isFullChunk());70-$notFullList = range(1, $halfRange);71-$selectionList2 = new SelectionList(72- priorityEntityIdList: $notFullList,73- normalEntityIdList: [],74- chunkSize: $chunkSize,75- );76-$this->assertFalse($selectionList2->isFullChunk());77-78-$priorityRange = range(1, $halfRange);79-$normalRange = range($halfRange + 1, $chunkSize);80-81-$selectionList3 = new SelectionList(82- priorityEntityIdList: $priorityRange,83- normalEntityIdList: $normalRange,84- chunkSize: $chunkSize,85- );86-$this->assertTrue($selectionList3->isFullChunk());87 }143 }88}144}</selection>” selected. Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
You said
I’m on page “<tabTitle>JY-20808 low priority indexing queue by Vasil-Jimi</tabTitle>” with “<selection>@@ -5,84 +5,140 @@5namespace Tests\Unit\Component\ES\Processor\DTOs;5namespace Tests\Unit\Component\ES\Processor\DTOs;667use Jiminny\Component\ES\Processor\DTOs\SelectionList;7use Jiminny\Component\ES\Processor\DTOs\SelectionList;8+use Jiminny\Component\ES\QueuePriorityEnum;8use PHPUnit\Framework\Attributes\CoversClass;9use PHPUnit\Framework\Attributes\CoversClass;9use PHPUnit\Framework\TestCase;10use PHPUnit\Framework\TestCase;101111#[CoversClass(SelectionList::class)]12#[CoversClass(SelectionList::class)]12final class SelectionListTest extends TestCase13final class SelectionListTest extends TestCase13{14{14-public function testGetEntityIds(): void15+private const int CHUNK_SIZE = 100;16+17+public function testAddEntityListAndGetAllIds(): void18+ {19+$selectionList = new SelectionList();20+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);21+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);22+23+$this->assertSame([1, 2, 3, 4], $selectionList->getAllIds());24+ }25+26+public function testAddEntityListMergesMultipleCallsForSamePriority(): void27+ {28+$selectionList = new SelectionList();29+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);30+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [3, 4]);31+32+$this->assertSame([1, 2, 3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));33+ }34+35+public function testGetEntityListItemsByGroup(): void36+ {37+$selectionList = new SelectionList();38+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);39+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);40+$selectionList->addEntityList(QueuePriorityEnum::LOW, [5, 6]);41+42+$this->assertSame([1, 2], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));43+$this->assertSame([3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::NORMAL));44+$this->assertSame([5, 6], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::LOW));45+ }46+47+public function testGetEntityListItemsByGroupReturnsEmptyArrayForUnknownGroup(): void15 {48 {16-$priority = ['p1', 'p2'];49+$selectionList = new SelectionList();17-$normal = ['n1', 'n2'];50+18-$selectionList = new SelectionList($priority, $normal);51+$this->assertSame([], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));52+ }195320-$this->assertSame($priority, $selectionList->getHighPriorityEntityIds());54+public function testGetEntityListGroups(): void21-$this->assertSame($normal, $selectionList->getNormalPriorityEntityId());55+ {56+$selectionList = new SelectionList();57+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);58+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2]);225923-$this->assertSame(['p1', 'p2', 'n1', 'n2'], $selectionList->getAllIds());60+$this->assertSame(['high', 'normal'], $selectionList->getEntityListGroups());24 }61 }256226public function testCountReturnsTotalCount(): void63public function testCountReturnsTotalCount(): void27 {64 {28-$selectionList = new SelectionList(['p1'], ['n1', 'n2']);65+$selectionList = new SelectionList();66+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);67+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2, 3]);68+29$this->assertSame(3, $selectionList->count());69$this->assertSame(3, $selectionList->count());30 }70 }317132-public function testIsEmptyReturnsTrueWhenBothListsAreEmpty(): void72+public function testIsEmptyReturnsTrueWhenNoEntitiesAdded(): void33 {73 {34-$selectionList = new SelectionList([], []);74+$selectionList = new SelectionList();75+35$this->assertTrue($selectionList->isEmpty());76$this->assertTrue($selectionList->isEmpty());36 }77 }377838-public function testIsEmptyReturnsFalseWhenAnyListIsNotEmpty(): void79+public function testIsEmptyReturnsFalseWhenEntitiesAdded(): void39 {80 {40-$selectionList = new SelectionList(['p1'], []);81+$selectionList = new SelectionList();41-$this->assertFalse($selectionList->isEmpty());82+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);428343-$selectionList2 = new SelectionList([], ['n1']);84+$this->assertFalse($selectionList->isEmpty());44-$this->assertFalse($selectionList2->isEmpty());45 }85 }468647-public function testIsStaleChunkSelected(): void87+public function testMarkStaleAndIsStaleChunkSelected(): void48 {88 {49-$selectionList = new SelectionList([], [], true);89+$selectionList = new SelectionList();50-$this->assertTrue($selectionList->isStaleChunkSelected());90+91+$this->assertFalse($selectionList->isStaleChunkSelected());92+93+$selectionList->markStale();519452-$selectionList2 = new SelectionList([], [], false);95+$this->assertTrue($selectionList->isStaleChunkSelected());53-$this->assertFalse($selectionList2->isStaleChunkSelected());54 }96 }559756public function testIsFullChunk(): void98public function testIsFullChunk(): void57 {99 {58-$chunkSize = 200;100+$selectionList = new SelectionList();59-101+$selectionList->setChunkSize(self::CHUNK_SIZE);60-$fullList = range(1, $chunkSize);102+61-$selectionList = new SelectionList(103+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, self::CHUNK_SIZE));62- priorityEntityIdList: $fullList,104+63- normalEntityIdList: [],105+$this->assertTrue($selectionList->isFullChunk());64- chunkSize: $chunkSize,106+ }65- );107+108+public function testIsNotFullChunkWhenBelowChunkSize(): void109+ {110+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);111+112+$selectionList = new SelectionList();113+$selectionList->setChunkSize(self::CHUNK_SIZE);114+115+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range(1, $halfRange));116+117+$this->assertFalse($selectionList->isFullChunk());118+ }119+120+public function testIsFullChunkAcrossMultiplePriorityGroups(): void121+ {122+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);123+124+$selectionList = new SelectionList();125+$selectionList->setChunkSize(self::CHUNK_SIZE);126+127+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, $halfRange));128+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range($halfRange + 1, self::CHUNK_SIZE));129+130+$this->assertTrue($selectionList->isFullChunk());131+ }132+133+public function testSetChunkSizeAffectsIsFullChunk(): void134+ {135+$selectionList = new SelectionList();136+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [1, 2, 3]);137+138+$selectionList->setChunkSize(3);66$this->assertTrue($selectionList->isFullChunk());139$this->assertTrue($selectionList->isFullChunk());6714068-$halfRange = (int) ceil($chunkSize / 2);141+$selectionList->setChunkSize(50);69-142+$this->assertFalse($selectionList->isFullChunk());70-$notFullList = range(1, $halfRange);71-$selectionList2 = new SelectionList(72- priorityEntityIdList: $notFullList,73- normalEntityIdList: [],74- chunkSize: $chunkSize,75- );76-$this->assertFalse($selectionList2->isFullChunk());77-78-$priorityRange = range(1, $halfRange);79-$normalRange = range($halfRange + 1, $chunkSize);80-81-$selectionList3 = new SelectionList(82- priorityEntityIdList: $priorityRange,83- normalEntityIdList: $normalRange,84- chunkSize: $chunkSize,85- );86-$this->assertTrue($selectionList3->isFullChunk());87 }143 }88}144}</selection>” selected.
Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
Expand
Listen
Show thinking
Gemini said
Gemini said
Here is a summary of the changes made to the
SelectionListTest
file, reflecting a significant refactoring of how the
SelectionList
class manages state and priorities.
Object Instantiation and State Management
Object Instantiation and State Management
Removed Constructor Injection:
The tests no longer pass arrays, chunk sizes, or boolean flags directly into the
SelectionList
constructor. Objects are now instantiated empty (
new SelectionList()
).
Introduced
addEntityList()
:
Added tests for populating the selection list dynamically using
addEntityList()
, which pairs a
QueuePriorityEnum
(e.g.,
HIGH
,
NORMAL
,
LOW
) with an array of IDs.
Merged Priorities:
Added tests confirming that invoking
addEntityList()
multiple times for the same priority group successfully merges the ID arrays.
Updated Data Retrieval
Updated Data Retrieval
Generic Group Getters:
Removed legacy priority-specific getters (e.g.,
getHighPriorityEntityIds()
). These are replaced by tests for
getEntityListItemsByGroup()
, which fetches IDs based on the provided enum.
Unknown Group Handling:
Added validation that
getEntityListItemsByGroup()
safely returns an empty array when querying an unpopulated priority group.
Group Listing:
Added
testGetEntityListGroups()
to verify the retrieval of all active priority group keys (e.g.,
['high', 'normal']
).
Aggregated Fetching:
Maintained and updated tests for
getAllIds()
to ensure it correctly flattens IDs across all newly structured priority groups.
Chunking and Flags
Chunking and Flags
Dynamic Chunk Sizing:
Introduced a
CHUNK_SIZE
constant and replaced constructor-based chunk sizing with a new
setChunkSize()
method.
Chunk Validation:
Expanded
isFullChunk()
tests to verify behavior when exactly at chunk capacity, below capacity, when capacities are split across multiple priority groups, and when the chunk size is changed dynamically.
Stale Status:
Replaced the constructor-injected stale flag with a new
markStale()
method, testing that
isStaleChunkSelected()
correctly toggles from false to true.
Utility Methods:
Updated tests for
count()
and
isEmpty()
to align with the new
addEntityList
structure rather than constructor arrays.
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...
|
[{"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":"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 I’m on page “<tabTitle>JY-20808 low priority indexing queue by Vasil-Jimi</tabTitle>” with “<selection>@@ -5,84 +5,140 @@5namespace Tests\\Unit\\Component\\ES\\Processor\\DTOs;5namespace Tests\\Unit\\Component\\ES\\Processor\\DTOs;667use Jiminny\\Component\\ES\\Processor\\DTOs\\SelectionList;7use Jiminny\\Component\\ES\\Processor\\DTOs\\SelectionList;8+use Jiminny\\Component\\ES\\QueuePriorityEnum;8use PHPUnit\\Framework\\Attributes\\CoversClass;9use PHPUnit\\Framework\\Attributes\\CoversClass;9use PHPUnit\\Framework\\TestCase;10use PHPUnit\\Framework\\TestCase;101111#[CoversClass(SelectionList::class)]12#[CoversClass(SelectionList::class)]12final class SelectionListTest extends TestCase13final class SelectionListTest extends TestCase13{14{14-public function testGetEntityIds(): void15+private const int CHUNK_SIZE = 100;16+17+public function testAddEntityListAndGetAllIds(): void18+ {19+$selectionList = new SelectionList();20+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);21+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);22+23+$this->assertSame([1, 2, 3, 4], $selectionList->getAllIds());24+ }25+26+public function testAddEntityListMergesMultipleCallsForSamePriority(): void27+ {28+$selectionList = new SelectionList();29+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);30+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [3, 4]);31+32+$this->assertSame([1, 2, 3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));33+ }34+35+public function testGetEntityListItemsByGroup(): void36+ {37+$selectionList = new SelectionList();38+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);39+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);40+$selectionList->addEntityList(QueuePriorityEnum::LOW, [5, 6]);41+42+$this->assertSame([1, 2], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));43+$this->assertSame([3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::NORMAL));44+$this->assertSame([5, 6], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::LOW));45+ }46+47+public function testGetEntityListItemsByGroupReturnsEmptyArrayForUnknownGroup(): void15 {48 {16-$priority = ['p1', 'p2'];49+$selectionList = new SelectionList();17-$normal = ['n1', 'n2'];50+18-$selectionList = new SelectionList($priority, $normal);51+$this->assertSame([], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));52+ }195320-$this->assertSame($priority, $selectionList->getHighPriorityEntityIds());54+public function testGetEntityListGroups(): void21-$this->assertSame($normal, $selectionList->getNormalPriorityEntityId());55+ {56+$selectionList = new SelectionList();57+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);58+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2]);225923-$this->assertSame(['p1', 'p2', 'n1', 'n2'], $selectionList->getAllIds());60+$this->assertSame(['high', 'normal'], $selectionList->getEntityListGroups());24 }61 }256226public function testCountReturnsTotalCount(): void63public function testCountReturnsTotalCount(): void27 {64 {28-$selectionList = new SelectionList(['p1'], ['n1', 'n2']);65+$selectionList = new SelectionList();66+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);67+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2, 3]);68+29$this->assertSame(3, $selectionList->count());69$this->assertSame(3, $selectionList->count());30 }70 }317132-public function testIsEmptyReturnsTrueWhenBothListsAreEmpty(): void72+public function testIsEmptyReturnsTrueWhenNoEntitiesAdded(): void33 {73 {34-$selectionList = new SelectionList([], []);74+$selectionList = new SelectionList();75+35$this->assertTrue($selectionList->isEmpty());76$this->assertTrue($selectionList->isEmpty());36 }77 }377838-public function testIsEmptyReturnsFalseWhenAnyListIsNotEmpty(): void79+public function testIsEmptyReturnsFalseWhenEntitiesAdded(): void39 {80 {40-$selectionList = new SelectionList(['p1'], []);81+$selectionList = new SelectionList();41-$this->assertFalse($selectionList->isEmpty());82+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);428343-$selectionList2 = new SelectionList([], ['n1']);84+$this->assertFalse($selectionList->isEmpty());44-$this->assertFalse($selectionList2->isEmpty());45 }85 }468647-public function testIsStaleChunkSelected(): void87+public function testMarkStaleAndIsStaleChunkSelected(): void48 {88 {49-$selectionList = new SelectionList([], [], true);89+$selectionList = new SelectionList();50-$this->assertTrue($selectionList->isStaleChunkSelected());90+91+$this->assertFalse($selectionList->isStaleChunkSelected());92+93+$selectionList->markStale();519452-$selectionList2 = new SelectionList([], [], false);95+$this->assertTrue($selectionList->isStaleChunkSelected());53-$this->assertFalse($selectionList2->isStaleChunkSelected());54 }96 }559756public function testIsFullChunk(): void98public function testIsFullChunk(): void57 {99 {58-$chunkSize = 200;100+$selectionList = new SelectionList();59-101+$selectionList->setChunkSize(self::CHUNK_SIZE);60-$fullList = range(1, $chunkSize);102+61-$selectionList = new SelectionList(103+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, self::CHUNK_SIZE));62- priorityEntityIdList: $fullList,104+63- normalEntityIdList: [],105+$this->assertTrue($selectionList->isFullChunk());64- chunkSize: $chunkSize,106+ }65- );107+108+public function testIsNotFullChunkWhenBelowChunkSize(): void109+ {110+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);111+112+$selectionList = new SelectionList();113+$selectionList->setChunkSize(self::CHUNK_SIZE);114+115+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range(1, $halfRange));116+117+$this->assertFalse($selectionList->isFullChunk());118+ }119+120+public function testIsFullChunkAcrossMultiplePriorityGroups(): void121+ {122+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);123+124+$selectionList = new SelectionList();125+$selectionList->setChunkSize(self::CHUNK_SIZE);126+127+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, $halfRange));128+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range($halfRange + 1, self::CHUNK_SIZE));129+130+$this->assertTrue($selectionList->isFullChunk());131+ }132+133+public function testSetChunkSizeAffectsIsFullChunk(): void134+ {135+$selectionList = new SelectionList();136+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [1, 2, 3]);137+138+$selectionList->setChunkSize(3);66$this->assertTrue($selectionList->isFullChunk());139$this->assertTrue($selectionList->isFullChunk());6714068-$halfRange = (int) ceil($chunkSize / 2);141+$selectionList->setChunkSize(50);69-142+$this->assertFalse($selectionList->isFullChunk());70-$notFullList = range(1, $halfRange);71-$selectionList2 = new SelectionList(72- priorityEntityIdList: $notFullList,73- normalEntityIdList: [],74- chunkSize: $chunkSize,75- );76-$this->assertFalse($selectionList2->isFullChunk());77-78-$priorityRange = range(1, $halfRange);79-$normalRange = range($halfRange + 1, $chunkSize);80-81-$selectionList3 = new SelectionList(82- priorityEntityIdList: $priorityRange,83- normalEntityIdList: $normalRange,84- chunkSize: $chunkSize,85- );86-$this->assertTrue($selectionList3->isFullChunk());87 }143 }88}144}</selection>” selected. Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.","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":"I’m on page “<tabTitle>JY-20808 low priority indexing queue by Vasil-Jimi</tabTitle>” with “<selection>@@ -5,84 +5,140 @@5namespace Tests\\Unit\\Component\\ES\\Processor\\DTOs;5namespace Tests\\Unit\\Component\\ES\\Processor\\DTOs;667use Jiminny\\Component\\ES\\Processor\\DTOs\\SelectionList;7use Jiminny\\Component\\ES\\Processor\\DTOs\\SelectionList;8+use Jiminny\\Component\\ES\\QueuePriorityEnum;8use PHPUnit\\Framework\\Attributes\\CoversClass;9use PHPUnit\\Framework\\Attributes\\CoversClass;9use PHPUnit\\Framework\\TestCase;10use PHPUnit\\Framework\\TestCase;101111#[CoversClass(SelectionList::class)]12#[CoversClass(SelectionList::class)]12final class SelectionListTest extends TestCase13final class SelectionListTest extends TestCase13{14{14-public function testGetEntityIds(): void15+private const int CHUNK_SIZE = 100;16+17+public function testAddEntityListAndGetAllIds(): void18+ {19+$selectionList = new SelectionList();20+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);21+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);22+23+$this->assertSame([1, 2, 3, 4], $selectionList->getAllIds());24+ }25+26+public function testAddEntityListMergesMultipleCallsForSamePriority(): void27+ {28+$selectionList = new SelectionList();29+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);30+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [3, 4]);31+32+$this->assertSame([1, 2, 3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));33+ }34+35+public function testGetEntityListItemsByGroup(): void36+ {37+$selectionList = new SelectionList();38+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);39+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);40+$selectionList->addEntityList(QueuePriorityEnum::LOW, [5, 6]);41+42+$this->assertSame([1, 2], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));43+$this->assertSame([3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::NORMAL));44+$this->assertSame([5, 6], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::LOW));45+ }46+47+public function testGetEntityListItemsByGroupReturnsEmptyArrayForUnknownGroup(): void15 {48 {16-$priority = ['p1', 'p2'];49+$selectionList = new SelectionList();17-$normal = ['n1', 'n2'];50+18-$selectionList = new SelectionList($priority, $normal);51+$this->assertSame([], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));52+ }195320-$this->assertSame($priority, $selectionList->getHighPriorityEntityIds());54+public function testGetEntityListGroups(): void21-$this->assertSame($normal, $selectionList->getNormalPriorityEntityId());55+ {56+$selectionList = new SelectionList();57+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);58+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2]);225923-$this->assertSame(['p1', 'p2', 'n1', 'n2'], $selectionList->getAllIds());60+$this->assertSame(['high', 'normal'], $selectionList->getEntityListGroups());24 }61 }256226public function testCountReturnsTotalCount(): void63public function testCountReturnsTotalCount(): void27 {64 {28-$selectionList = new SelectionList(['p1'], ['n1', 'n2']);65+$selectionList = new SelectionList();66+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);67+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2, 3]);68+29$this->assertSame(3, $selectionList->count());69$this->assertSame(3, $selectionList->count());30 }70 }317132-public function testIsEmptyReturnsTrueWhenBothListsAreEmpty(): void72+public function testIsEmptyReturnsTrueWhenNoEntitiesAdded(): void33 {73 {34-$selectionList = new SelectionList([], []);74+$selectionList = new SelectionList();75+35$this->assertTrue($selectionList->isEmpty());76$this->assertTrue($selectionList->isEmpty());36 }77 }377838-public function testIsEmptyReturnsFalseWhenAnyListIsNotEmpty(): void79+public function testIsEmptyReturnsFalseWhenEntitiesAdded(): void39 {80 {40-$selectionList = new SelectionList(['p1'], []);81+$selectionList = new SelectionList();41-$this->assertFalse($selectionList->isEmpty());82+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);428343-$selectionList2 = new SelectionList([], ['n1']);84+$this->assertFalse($selectionList->isEmpty());44-$this->assertFalse($selectionList2->isEmpty());45 }85 }468647-public function testIsStaleChunkSelected(): void87+public function testMarkStaleAndIsStaleChunkSelected(): void48 {88 {49-$selectionList = new SelectionList([], [], true);89+$selectionList = new SelectionList();50-$this->assertTrue($selectionList->isStaleChunkSelected());90+91+$this->assertFalse($selectionList->isStaleChunkSelected());92+93+$selectionList->markStale();519452-$selectionList2 = new SelectionList([], [], false);95+$this->assertTrue($selectionList->isStaleChunkSelected());53-$this->assertFalse($selectionList2->isStaleChunkSelected());54 }96 }559756public function testIsFullChunk(): void98public function testIsFullChunk(): void57 {99 {58-$chunkSize = 200;100+$selectionList = new SelectionList();59-101+$selectionList->setChunkSize(self::CHUNK_SIZE);60-$fullList = range(1, $chunkSize);102+61-$selectionList = new SelectionList(103+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, self::CHUNK_SIZE));62- priorityEntityIdList: $fullList,104+63- normalEntityIdList: [],105+$this->assertTrue($selectionList->isFullChunk());64- chunkSize: $chunkSize,106+ }65- );107+108+public function testIsNotFullChunkWhenBelowChunkSize(): void109+ {110+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);111+112+$selectionList = new SelectionList();113+$selectionList->setChunkSize(self::CHUNK_SIZE);114+115+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range(1, $halfRange));116+117+$this->assertFalse($selectionList->isFullChunk());118+ }119+120+public function testIsFullChunkAcrossMultiplePriorityGroups(): void121+ {122+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);123+124+$selectionList = new SelectionList();125+$selectionList->setChunkSize(self::CHUNK_SIZE);126+127+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, $halfRange));128+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range($halfRange + 1, self::CHUNK_SIZE));129+130+$this->assertTrue($selectionList->isFullChunk());131+ }132+133+public function testSetChunkSizeAffectsIsFullChunk(): void134+ {135+$selectionList = new SelectionList();136+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [1, 2, 3]);137+138+$selectionList->setChunkSize(3);66$this->assertTrue($selectionList->isFullChunk());139$this->assertTrue($selectionList->isFullChunk());6714068-$halfRange = (int) ceil($chunkSize / 2);141+$selectionList->setChunkSize(50);69-142+$this->assertFalse($selectionList->isFullChunk());70-$notFullList = range(1, $halfRange);71-$selectionList2 = new SelectionList(72- priorityEntityIdList: $notFullList,73- normalEntityIdList: [],74- chunkSize: $chunkSize,75- );76-$this->assertFalse($selectionList2->isFullChunk());77-78-$priorityRange = range(1, $halfRange);79-$normalRange = range($halfRange + 1, $chunkSize);80-81-$selectionList3 = new SelectionList(82- priorityEntityIdList: $priorityRange,83- normalEntityIdList: $normalRange,84- chunkSize: $chunkSize,85- );86-$this->assertTrue($selectionList3->isFullChunk());87 }143 }88}144}</selection>” selected.","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Expand","depth":21,"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"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":"Here is a summary of the changes made to the","depth":24,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SelectionListTest","depth":25,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"file, reflecting a significant refactoring of how the","depth":24,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SelectionList","depth":25,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"class manages state and priorities.","depth":24,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Object Instantiation and State Management","depth":23,"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Object Instantiation and State Management","depth":24,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Removed Constructor Injection:","depth":26,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The tests no longer pass arrays, chunk sizes, or boolean flags directly into the","depth":26,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SelectionList","depth":27,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"constructor. Objects are now instantiated empty (","depth":26,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"new SelectionList()","depth":27,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":").","depth":26,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Introduced","depth":26,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"addEntityList()","depth":27,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":":","depth":26,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Added tests for populating the selection list dynamically using","depth":26,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"addEntityList()","depth":27,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":", which pairs a","depth":26,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"QueuePriorityEnum","depth":27,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(e.g.,","depth":26,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"HIGH","depth":27,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":26,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"NORMAL","depth":27,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":26,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"LOW","depth":27,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":") with an array of IDs.","depth":26,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Merged Priorities:","depth":26,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Added tests confirming that invoking","depth":26,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"addEntityList()","depth":27,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"multiple times for the same priority group successfully merges the ID arrays.","depth":26,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Updated Data Retrieval","depth":23,"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Updated Data Retrieval","depth":24,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Generic Group Getters:","depth":26,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Removed legacy priority-specific getters (e.g.,","depth":26,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"getHighPriorityEntityIds()","depth":27,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"). These are replaced by tests for","depth":26,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"getEntityListItemsByGroup()","depth":27,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":", which fetches IDs based on the provided enum.","depth":26,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Unknown Group Handling:","depth":26,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Added validation that","depth":26,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"getEntityListItemsByGroup()","depth":27,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"safely returns an empty array when querying an unpopulated priority group.","depth":26,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Group Listing:","depth":26,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Added","depth":26,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"testGetEntityListGroups()","depth":27,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"to verify the retrieval of all active priority group keys (e.g.,","depth":26,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"['high', 'normal']","depth":27,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":").","depth":26,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Aggregated Fetching:","depth":26,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Maintained and updated tests for","depth":26,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"getAllIds()","depth":27,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"to ensure it correctly flattens IDs across all newly structured priority groups.","depth":26,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Chunking and Flags","depth":23,"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Chunking and Flags","depth":24,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Dynamic Chunk Sizing:","depth":26,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Introduced a","depth":26,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"CHUNK_SIZE","depth":27,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"constant and replaced constructor-based chunk sizing with a new","depth":26,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"setChunkSize()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"method.","depth":26,"bounds":{"left":0.0,"top":0.0044444446,"width":0.044791665,"height":0.022777777},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Chunk Validation:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Expanded","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"isFullChunk()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"tests to verify behavior when exactly at chunk capacity, below capacity, when capacities are split across multiple priority groups, and when the chunk size is changed dynamically.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Stale Status:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Replaced the constructor-injected stale flag with a new","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"markStale()","depth":27,"bounds":{"left":0.05590278,"top":0.155,"width":0.06388889,"height":0.020555556},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"method, testing that","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"isStaleChunkSelected()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"correctly toggles from false to true.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Utility Methods:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Updated tests for","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"count()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"and","depth":26,"bounds":{"left":0.0,"top":0.22777778,"width":0.024652777,"height":0.022777777},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"isEmpty()","depth":27,"bounds":{"left":0.0,"top":0.22944444,"width":0.052430555,"height":0.020555556},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"to align with the new","depth":26,"bounds":{"left":0.013888889,"top":0.22777778,"width":0.110069446,"height":0.022777777},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"addEntityList","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"structure rather than constructor arrays.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Good response","depth":21,"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":21,"on_screen":false,"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":false,"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":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy","depth":21,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Show more options","depth":20,"on_screen":false,"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":true,"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":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"},{"role":"AXStaticText","text":"12082","depth":15,"on_screen":true,"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":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
599784360278297322
|
3554570464346790301
|
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
Copy prompt
Edit
You said I’m on page “<tabTitle>JY-20808 low priority indexing queue by Vasil-Jimi</tabTitle>” with “<selection>@@ -5,84 +5,140 @@5namespace Tests\Unit\Component\ES\Processor\DTOs;5namespace Tests\Unit\Component\ES\Processor\DTOs;667use Jiminny\Component\ES\Processor\DTOs\SelectionList;7use Jiminny\Component\ES\Processor\DTOs\SelectionList;8+use Jiminny\Component\ES\QueuePriorityEnum;8use PHPUnit\Framework\Attributes\CoversClass;9use PHPUnit\Framework\Attributes\CoversClass;9use PHPUnit\Framework\TestCase;10use PHPUnit\Framework\TestCase;101111#[CoversClass(SelectionList::class)]12#[CoversClass(SelectionList::class)]12final class SelectionListTest extends TestCase13final class SelectionListTest extends TestCase13{14{14-public function testGetEntityIds(): void15+private const int CHUNK_SIZE = 100;16+17+public function testAddEntityListAndGetAllIds(): void18+ {19+$selectionList = new SelectionList();20+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);21+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);22+23+$this->assertSame([1, 2, 3, 4], $selectionList->getAllIds());24+ }25+26+public function testAddEntityListMergesMultipleCallsForSamePriority(): void27+ {28+$selectionList = new SelectionList();29+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);30+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [3, 4]);31+32+$this->assertSame([1, 2, 3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));33+ }34+35+public function testGetEntityListItemsByGroup(): void36+ {37+$selectionList = new SelectionList();38+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);39+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);40+$selectionList->addEntityList(QueuePriorityEnum::LOW, [5, 6]);41+42+$this->assertSame([1, 2], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));43+$this->assertSame([3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::NORMAL));44+$this->assertSame([5, 6], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::LOW));45+ }46+47+public function testGetEntityListItemsByGroupReturnsEmptyArrayForUnknownGroup(): void15 {48 {16-$priority = ['p1', 'p2'];49+$selectionList = new SelectionList();17-$normal = ['n1', 'n2'];50+18-$selectionList = new SelectionList($priority, $normal);51+$this->assertSame([], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));52+ }195320-$this->assertSame($priority, $selectionList->getHighPriorityEntityIds());54+public function testGetEntityListGroups(): void21-$this->assertSame($normal, $selectionList->getNormalPriorityEntityId());55+ {56+$selectionList = new SelectionList();57+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);58+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2]);225923-$this->assertSame(['p1', 'p2', 'n1', 'n2'], $selectionList->getAllIds());60+$this->assertSame(['high', 'normal'], $selectionList->getEntityListGroups());24 }61 }256226public function testCountReturnsTotalCount(): void63public function testCountReturnsTotalCount(): void27 {64 {28-$selectionList = new SelectionList(['p1'], ['n1', 'n2']);65+$selectionList = new SelectionList();66+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);67+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2, 3]);68+29$this->assertSame(3, $selectionList->count());69$this->assertSame(3, $selectionList->count());30 }70 }317132-public function testIsEmptyReturnsTrueWhenBothListsAreEmpty(): void72+public function testIsEmptyReturnsTrueWhenNoEntitiesAdded(): void33 {73 {34-$selectionList = new SelectionList([], []);74+$selectionList = new SelectionList();75+35$this->assertTrue($selectionList->isEmpty());76$this->assertTrue($selectionList->isEmpty());36 }77 }377838-public function testIsEmptyReturnsFalseWhenAnyListIsNotEmpty(): void79+public function testIsEmptyReturnsFalseWhenEntitiesAdded(): void39 {80 {40-$selectionList = new SelectionList(['p1'], []);81+$selectionList = new SelectionList();41-$this->assertFalse($selectionList->isEmpty());82+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);428343-$selectionList2 = new SelectionList([], ['n1']);84+$this->assertFalse($selectionList->isEmpty());44-$this->assertFalse($selectionList2->isEmpty());45 }85 }468647-public function testIsStaleChunkSelected(): void87+public function testMarkStaleAndIsStaleChunkSelected(): void48 {88 {49-$selectionList = new SelectionList([], [], true);89+$selectionList = new SelectionList();50-$this->assertTrue($selectionList->isStaleChunkSelected());90+91+$this->assertFalse($selectionList->isStaleChunkSelected());92+93+$selectionList->markStale();519452-$selectionList2 = new SelectionList([], [], false);95+$this->assertTrue($selectionList->isStaleChunkSelected());53-$this->assertFalse($selectionList2->isStaleChunkSelected());54 }96 }559756public function testIsFullChunk(): void98public function testIsFullChunk(): void57 {99 {58-$chunkSize = 200;100+$selectionList = new SelectionList();59-101+$selectionList->setChunkSize(self::CHUNK_SIZE);60-$fullList = range(1, $chunkSize);102+61-$selectionList = new SelectionList(103+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, self::CHUNK_SIZE));62- priorityEntityIdList: $fullList,104+63- normalEntityIdList: [],105+$this->assertTrue($selectionList->isFullChunk());64- chunkSize: $chunkSize,106+ }65- );107+108+public function testIsNotFullChunkWhenBelowChunkSize(): void109+ {110+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);111+112+$selectionList = new SelectionList();113+$selectionList->setChunkSize(self::CHUNK_SIZE);114+115+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range(1, $halfRange));116+117+$this->assertFalse($selectionList->isFullChunk());118+ }119+120+public function testIsFullChunkAcrossMultiplePriorityGroups(): void121+ {122+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);123+124+$selectionList = new SelectionList();125+$selectionList->setChunkSize(self::CHUNK_SIZE);126+127+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, $halfRange));128+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range($halfRange + 1, self::CHUNK_SIZE));129+130+$this->assertTrue($selectionList->isFullChunk());131+ }132+133+public function testSetChunkSizeAffectsIsFullChunk(): void134+ {135+$selectionList = new SelectionList();136+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [1, 2, 3]);137+138+$selectionList->setChunkSize(3);66$this->assertTrue($selectionList->isFullChunk());139$this->assertTrue($selectionList->isFullChunk());6714068-$halfRange = (int) ceil($chunkSize / 2);141+$selectionList->setChunkSize(50);69-142+$this->assertFalse($selectionList->isFullChunk());70-$notFullList = range(1, $halfRange);71-$selectionList2 = new SelectionList(72- priorityEntityIdList: $notFullList,73- normalEntityIdList: [],74- chunkSize: $chunkSize,75- );76-$this->assertFalse($selectionList2->isFullChunk());77-78-$priorityRange = range(1, $halfRange);79-$normalRange = range($halfRange + 1, $chunkSize);80-81-$selectionList3 = new SelectionList(82- priorityEntityIdList: $priorityRange,83- normalEntityIdList: $normalRange,84- chunkSize: $chunkSize,85- );86-$this->assertTrue($selectionList3->isFullChunk());87 }143 }88}144}</selection>” selected. Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
You said
I’m on page “<tabTitle>JY-20808 low priority indexing queue by Vasil-Jimi</tabTitle>” with “<selection>@@ -5,84 +5,140 @@5namespace Tests\Unit\Component\ES\Processor\DTOs;5namespace Tests\Unit\Component\ES\Processor\DTOs;667use Jiminny\Component\ES\Processor\DTOs\SelectionList;7use Jiminny\Component\ES\Processor\DTOs\SelectionList;8+use Jiminny\Component\ES\QueuePriorityEnum;8use PHPUnit\Framework\Attributes\CoversClass;9use PHPUnit\Framework\Attributes\CoversClass;9use PHPUnit\Framework\TestCase;10use PHPUnit\Framework\TestCase;101111#[CoversClass(SelectionList::class)]12#[CoversClass(SelectionList::class)]12final class SelectionListTest extends TestCase13final class SelectionListTest extends TestCase13{14{14-public function testGetEntityIds(): void15+private const int CHUNK_SIZE = 100;16+17+public function testAddEntityListAndGetAllIds(): void18+ {19+$selectionList = new SelectionList();20+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);21+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);22+23+$this->assertSame([1, 2, 3, 4], $selectionList->getAllIds());24+ }25+26+public function testAddEntityListMergesMultipleCallsForSamePriority(): void27+ {28+$selectionList = new SelectionList();29+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);30+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [3, 4]);31+32+$this->assertSame([1, 2, 3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));33+ }34+35+public function testGetEntityListItemsByGroup(): void36+ {37+$selectionList = new SelectionList();38+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);39+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);40+$selectionList->addEntityList(QueuePriorityEnum::LOW, [5, 6]);41+42+$this->assertSame([1, 2], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));43+$this->assertSame([3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::NORMAL));44+$this->assertSame([5, 6], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::LOW));45+ }46+47+public function testGetEntityListItemsByGroupReturnsEmptyArrayForUnknownGroup(): void15 {48 {16-$priority = ['p1', 'p2'];49+$selectionList = new SelectionList();17-$normal = ['n1', 'n2'];50+18-$selectionList = new SelectionList($priority, $normal);51+$this->assertSame([], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));52+ }195320-$this->assertSame($priority, $selectionList->getHighPriorityEntityIds());54+public function testGetEntityListGroups(): void21-$this->assertSame($normal, $selectionList->getNormalPriorityEntityId());55+ {56+$selectionList = new SelectionList();57+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);58+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2]);225923-$this->assertSame(['p1', 'p2', 'n1', 'n2'], $selectionList->getAllIds());60+$this->assertSame(['high', 'normal'], $selectionList->getEntityListGroups());24 }61 }256226public function testCountReturnsTotalCount(): void63public function testCountReturnsTotalCount(): void27 {64 {28-$selectionList = new SelectionList(['p1'], ['n1', 'n2']);65+$selectionList = new SelectionList();66+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);67+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2, 3]);68+29$this->assertSame(3, $selectionList->count());69$this->assertSame(3, $selectionList->count());30 }70 }317132-public function testIsEmptyReturnsTrueWhenBothListsAreEmpty(): void72+public function testIsEmptyReturnsTrueWhenNoEntitiesAdded(): void33 {73 {34-$selectionList = new SelectionList([], []);74+$selectionList = new SelectionList();75+35$this->assertTrue($selectionList->isEmpty());76$this->assertTrue($selectionList->isEmpty());36 }77 }377838-public function testIsEmptyReturnsFalseWhenAnyListIsNotEmpty(): void79+public function testIsEmptyReturnsFalseWhenEntitiesAdded(): void39 {80 {40-$selectionList = new SelectionList(['p1'], []);81+$selectionList = new SelectionList();41-$this->assertFalse($selectionList->isEmpty());82+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);428343-$selectionList2 = new SelectionList([], ['n1']);84+$this->assertFalse($selectionList->isEmpty());44-$this->assertFalse($selectionList2->isEmpty());45 }85 }468647-public function testIsStaleChunkSelected(): void87+public function testMarkStaleAndIsStaleChunkSelected(): void48 {88 {49-$selectionList = new SelectionList([], [], true);89+$selectionList = new SelectionList();50-$this->assertTrue($selectionList->isStaleChunkSelected());90+91+$this->assertFalse($selectionList->isStaleChunkSelected());92+93+$selectionList->markStale();519452-$selectionList2 = new SelectionList([], [], false);95+$this->assertTrue($selectionList->isStaleChunkSelected());53-$this->assertFalse($selectionList2->isStaleChunkSelected());54 }96 }559756public function testIsFullChunk(): void98public function testIsFullChunk(): void57 {99 {58-$chunkSize = 200;100+$selectionList = new SelectionList();59-101+$selectionList->setChunkSize(self::CHUNK_SIZE);60-$fullList = range(1, $chunkSize);102+61-$selectionList = new SelectionList(103+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, self::CHUNK_SIZE));62- priorityEntityIdList: $fullList,104+63- normalEntityIdList: [],105+$this->assertTrue($selectionList->isFullChunk());64- chunkSize: $chunkSize,106+ }65- );107+108+public function testIsNotFullChunkWhenBelowChunkSize(): void109+ {110+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);111+112+$selectionList = new SelectionList();113+$selectionList->setChunkSize(self::CHUNK_SIZE);114+115+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range(1, $halfRange));116+117+$this->assertFalse($selectionList->isFullChunk());118+ }119+120+public function testIsFullChunkAcrossMultiplePriorityGroups(): void121+ {122+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);123+124+$selectionList = new SelectionList();125+$selectionList->setChunkSize(self::CHUNK_SIZE);126+127+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, $halfRange));128+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range($halfRange + 1, self::CHUNK_SIZE));129+130+$this->assertTrue($selectionList->isFullChunk());131+ }132+133+public function testSetChunkSizeAffectsIsFullChunk(): void134+ {135+$selectionList = new SelectionList();136+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [1, 2, 3]);137+138+$selectionList->setChunkSize(3);66$this->assertTrue($selectionList->isFullChunk());139$this->assertTrue($selectionList->isFullChunk());6714068-$halfRange = (int) ceil($chunkSize / 2);141+$selectionList->setChunkSize(50);69-142+$this->assertFalse($selectionList->isFullChunk());70-$notFullList = range(1, $halfRange);71-$selectionList2 = new SelectionList(72- priorityEntityIdList: $notFullList,73- normalEntityIdList: [],74- chunkSize: $chunkSize,75- );76-$this->assertFalse($selectionList2->isFullChunk());77-78-$priorityRange = range(1, $halfRange);79-$normalRange = range($halfRange + 1, $chunkSize);80-81-$selectionList3 = new SelectionList(82- priorityEntityIdList: $priorityRange,83- normalEntityIdList: $normalRange,84- chunkSize: $chunkSize,85- );86-$this->assertTrue($selectionList3->isFullChunk());87 }143 }88}144}</selection>” selected.
Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
Expand
Listen
Show thinking
Gemini said
Gemini said
Here is a summary of the changes made to the
SelectionListTest
file, reflecting a significant refactoring of how the
SelectionList
class manages state and priorities.
Object Instantiation and State Management
Object Instantiation and State Management
Removed Constructor Injection:
The tests no longer pass arrays, chunk sizes, or boolean flags directly into the
SelectionList
constructor. Objects are now instantiated empty (
new SelectionList()
).
Introduced
addEntityList()
:
Added tests for populating the selection list dynamically using
addEntityList()
, which pairs a
QueuePriorityEnum
(e.g.,
HIGH
,
NORMAL
,
LOW
) with an array of IDs.
Merged Priorities:
Added tests confirming that invoking
addEntityList()
multiple times for the same priority group successfully merges the ID arrays.
Updated Data Retrieval
Updated Data Retrieval
Generic Group Getters:
Removed legacy priority-specific getters (e.g.,
getHighPriorityEntityIds()
). These are replaced by tests for
getEntityListItemsByGroup()
, which fetches IDs based on the provided enum.
Unknown Group Handling:
Added validation that
getEntityListItemsByGroup()
safely returns an empty array when querying an unpopulated priority group.
Group Listing:
Added
testGetEntityListGroups()
to verify the retrieval of all active priority group keys (e.g.,
['high', 'normal']
).
Aggregated Fetching:
Maintained and updated tests for
getAllIds()
to ensure it correctly flattens IDs across all newly structured priority groups.
Chunking and Flags
Chunking and Flags
Dynamic Chunk Sizing:
Introduced a
CHUNK_SIZE
constant and replaced constructor-based chunk sizing with a new
setChunkSize()
method.
Chunk Validation:
Expanded
isFullChunk()
tests to verify behavior when exactly at chunk capacity, below capacity, when capacities are split across multiple priority groups, and when the chunk size is changed dynamically.
Stale Status:
Replaced the constructor-injected stale flag with a new
markStale()
method, testing that
isStaleChunkSelected()
correctly toggles from false to true.
Utility Methods:
Updated tests for
count()
and
isEmpty()
to align with the new
addEntityList
structure rather than constructor arrays.
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...
|
55661
|
NULL
|
NULL
|
NULL
|
|
55664
|
1933
|
1
|
2026-05-19T06:37:33.250116+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779172653250_m2.jpg...
|
Firefox
|
NULL
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
claudecalVIeWWindowmelp0, Chat:= Cowork‹/> Code claudecalVIeWWindowmelp0, Chat:= Cowork‹/> Code+ New chatã Projectso0 Arutacts₴ CustomizePinnedBu garian cit zenshio apolication proces:Dawarich location tracking projectkecent love experiencesCities visited this veanDidI drive todavLast visit to LovechMonthly spending breakdown and regulaswimming visits this vearScreenbipe orune database vacuum erroMarking text locations in Screenpipe fraUpdating packages in LaravelScreenpipe data sync and retention manaScreenpipe sync script failing after recerHubspot BadRequest headers debuggingMonthlv expense trackingExoorting transaction data from Notion® How much have I spent for groc...April 2026 spending by categoryCode diff reviewHubSpot rate limit implementation strateScreenoioe retention oolicy code locaticViewing retention nolicv in screennine* Happy Tuesday, LukasHow can I help you today?Opus 4.7 Adaptive vO WriteO LearnCodeÖ Life stuff Claude's choiceRelaunch to updatelK Lukas. ProEl Checks 3Files changed 18v app/Component/ES/Listeners/UpdateMultipleTargetsListener.php C *@ -5,6 +5,7 @namespace J1minny_Component ES-L1steners;use Jiminny Component ES AsyncUpdateElasticSearch:use Jiminny Contracts ES Events UpdateMultipleEntities:use Psr|Log\LoggerInterface;@ -26,7 +27,7 @ public function handle(UpdateMultipleEntities $event): voidAsyncUpdatet lasticsearch: : bulkMarkcnt1t1esrorupdatesevent->getUpdateTargetValue(),Sevent->getcntltles.Sevent->isPriority()v app/Component/ES/Listeners/UpdateSingleTargetListener.php 0 *dd -9,0 +9.1 dduse 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'entityld' = $event->getEntityId(),if (Sevent->isSyncEvent()) {Sthis->handleSyncEvent(Sevent);$0namespace Jiminny.couse Jiminny Componel+ use Jiminny|Componenuse Jiminny Contractuse Psr\Log\LoggerInAsyncupdatedsevent->sevent->Sevent→f Daily - Platform • in 8mO All-In-OneC Capture AreaC. Capture Previous AreaCapture FullscreenCapture Windowi Scrolling CaptureU Self-TimerAa Capture Text (OCR)C Record Screen( Hide Desktop IconsD Open...$ Pin to the Screen…D Capture History...About CleanShot…Check for Updates...Settings...Quitwdso4-883TOTR100% C/ &• Tue 19 May 9:37:32+432 -159 8082|+2-1882ViewediGH : QueuePriorityEnum: :NORMAL,+9 -1 •0• Vieweduse Jiminny|Component\ES\Actions\TrackElasticSearchOperations;use Jiminny Component ts 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(),1* important:* Synchronous event should eventually be deprecated.* Instant write onerations are blockina and should be used soarinalv.* It is much better in terms of performance to write 100 or 1000 documents atonce,* and have one blocking reindex operation, instead of writing 10 documentssynchronously.if (sevent->icSvncFvent()) {|Sthis->handleSyncEvent(Sevent);...
|
NULL
|
5088877581275730948
|
NULL
|
visual_change
|
ocr
|
NULL
|
claudecalVIeWWindowmelp0, Chat:= Cowork‹/> Code claudecalVIeWWindowmelp0, Chat:= Cowork‹/> Code+ New chatã Projectso0 Arutacts₴ CustomizePinnedBu garian cit zenshio apolication proces:Dawarich location tracking projectkecent love experiencesCities visited this veanDidI drive todavLast visit to LovechMonthly spending breakdown and regulaswimming visits this vearScreenbipe orune database vacuum erroMarking text locations in Screenpipe fraUpdating packages in LaravelScreenpipe data sync and retention manaScreenpipe sync script failing after recerHubspot BadRequest headers debuggingMonthlv expense trackingExoorting transaction data from Notion® How much have I spent for groc...April 2026 spending by categoryCode diff reviewHubSpot rate limit implementation strateScreenoioe retention oolicy code locaticViewing retention nolicv in screennine* Happy Tuesday, LukasHow can I help you today?Opus 4.7 Adaptive vO WriteO LearnCodeÖ Life stuff Claude's choiceRelaunch to updatelK Lukas. ProEl Checks 3Files changed 18v app/Component/ES/Listeners/UpdateMultipleTargetsListener.php C *@ -5,6 +5,7 @namespace J1minny_Component ES-L1steners;use Jiminny Component ES AsyncUpdateElasticSearch:use Jiminny Contracts ES Events UpdateMultipleEntities:use Psr|Log\LoggerInterface;@ -26,7 +27,7 @ public function handle(UpdateMultipleEntities $event): voidAsyncUpdatet lasticsearch: : bulkMarkcnt1t1esrorupdatesevent->getUpdateTargetValue(),Sevent->getcntltles.Sevent->isPriority()v app/Component/ES/Listeners/UpdateSingleTargetListener.php 0 *dd -9,0 +9.1 dduse 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'entityld' = $event->getEntityId(),if (Sevent->isSyncEvent()) {Sthis->handleSyncEvent(Sevent);$0namespace Jiminny.couse Jiminny Componel+ use Jiminny|Componenuse Jiminny Contractuse Psr\Log\LoggerInAsyncupdatedsevent->sevent->Sevent→f Daily - Platform • in 8mO All-In-OneC Capture AreaC. Capture Previous AreaCapture FullscreenCapture Windowi Scrolling CaptureU Self-TimerAa Capture Text (OCR)C Record Screen( Hide Desktop IconsD Open...$ Pin to the Screen…D Capture History...About CleanShot…Check for Updates...Settings...Quitwdso4-883TOTR100% C/ &• Tue 19 May 9:37:32+432 -159 8082|+2-1882ViewediGH : QueuePriorityEnum: :NORMAL,+9 -1 •0• Vieweduse Jiminny|Component\ES\Actions\TrackElasticSearchOperations;use Jiminny Component ts 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(),1* important:* Synchronous event should eventually be deprecated.* Instant write onerations are blockina and should be used soarinalv.* It is much better in terms of performance to write 100 or 1000 documents atonce,* and have one blocking reindex operation, instead of writing 10 documentssynchronously.if (sevent->icSvncFvent()) {|Sthis->handleSyncEvent(Sevent);...
|
55662
|
NULL
|
NULL
|
NULL
|
|
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
|
|
55666
|
1933
|
2
|
2026-05-19T06:37:37.144658+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779172657144_m2.jpg...
|
Firefox
|
NULL
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
claudecalVIewWindowmelp0, Chat:= Cowork‹/> Code claudecalVIewWindowmelp0, Chat:= Cowork‹/> Code+ New chatã Projectso0 Arutacts₴ CustomizePinnedBu garian cit zenshio apolication proces:Dawarich location tracking projectkecent love experiencesCities visited this veanDidI drive todavLast visit to LovechMonthly spending breakdown and regulaswimming visits this vearScreenbipe orune database vacuum erroMarking text locations in Screenpipe fraUpdating packages in LaravelScreenpipe data sync and retention manaScreenpipe sync script failing after recerHubspot BadRequest headers debuggingMonthlv expense trackingExoorting transaction data from Notion® How much have I spent for groc...April 2026 spending by categoryCode diff reviewHubSpot rate limit implementation strateScreenoioe retention oolicy code locaticViewing retention nolicv in screennine* Happy Tuesday, LukasHow can I help you today?Opus 4.7 Adaptive vO WriteO LearnCodeÖ Life stuff Claude's choiceRelaunch to updatelK Lukas. ProEl Checks 3* Files changed 18v app/Component/ES/Listeners/UpdateMultipleTargetsListener.php C *@ -5,6 +5,7 @namespace J1minny_Component ES-L1steners;use Jiminny Component ES AsyncUpdateElasticSearch:use Jiminny Contracts ES Events UpdateMultipleEntities:use Psr|Log\LoggerInterface;@ -26,7 +27,7 @ public function handle(UpdateMultipleEntities $event): voidAsyncUpdatet lasticsearch: : bulkMarkcnt1t1esrorupdatesevent->getUpdateTargetValue(),Sevent->getcntltles.Sevent->isPriority()v app/Component/ES/Listeners/UpdateSingleTargetListener.php 0 *dd -9,0 +9.1 dduse 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->isSyncEvent()) {Sthis->handleSyncEvent(Sevent);$0namespace Jiminny.couse Jiminny Componel+ use Jiminny|Componenuse Jiminny Contractuse Psr\Log\LoggerInAsyncupdatedsevent->sevent->Sevent→f Daily - Platform • in 8mO All-In-One( Capture AreaC. Capture Previous Area- Capture Fullscreen• Capture WindowJ Scrolling CaptureU Self-TimerAa Capture Text (OCR)C Record Screen( Hide Desktop IconsD Open...$ Pin to the Screen…D Capture History...About CleanShot…Check for Updates...Settings...Quitwdso4-883TKTOTR100% LzP8• Tue 19 May 9:37:36+432 -159 8082|+2-1882ViewediGH : QueuePriorityEnum: :NORMAL,+9 -1 •0• Vieweduse Jiminny|Component\ES\Actions\TrackElasticSearchOperations;use Jiminny Component ts 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(),1* important:* Synchronous event should eventually be deprecated.* Instant write onerations are blockina and should be used soarinalv.* 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->icSvncFvent()) {|Sthis->handleSyncEvent(Sevent);...
|
NULL
|
-1026932756735150629
|
NULL
|
click
|
ocr
|
NULL
|
claudecalVIewWindowmelp0, Chat:= Cowork‹/> Code claudecalVIewWindowmelp0, Chat:= Cowork‹/> Code+ New chatã Projectso0 Arutacts₴ CustomizePinnedBu garian cit zenshio apolication proces:Dawarich location tracking projectkecent love experiencesCities visited this veanDidI drive todavLast visit to LovechMonthly spending breakdown and regulaswimming visits this vearScreenbipe orune database vacuum erroMarking text locations in Screenpipe fraUpdating packages in LaravelScreenpipe data sync and retention manaScreenpipe sync script failing after recerHubspot BadRequest headers debuggingMonthlv expense trackingExoorting transaction data from Notion® How much have I spent for groc...April 2026 spending by categoryCode diff reviewHubSpot rate limit implementation strateScreenoioe retention oolicy code locaticViewing retention nolicv in screennine* Happy Tuesday, LukasHow can I help you today?Opus 4.7 Adaptive vO WriteO LearnCodeÖ Life stuff Claude's choiceRelaunch to updatelK Lukas. ProEl Checks 3* Files changed 18v app/Component/ES/Listeners/UpdateMultipleTargetsListener.php C *@ -5,6 +5,7 @namespace J1minny_Component ES-L1steners;use Jiminny Component ES AsyncUpdateElasticSearch:use Jiminny Contracts ES Events UpdateMultipleEntities:use Psr|Log\LoggerInterface;@ -26,7 +27,7 @ public function handle(UpdateMultipleEntities $event): voidAsyncUpdatet lasticsearch: : bulkMarkcnt1t1esrorupdatesevent->getUpdateTargetValue(),Sevent->getcntltles.Sevent->isPriority()v app/Component/ES/Listeners/UpdateSingleTargetListener.php 0 *dd -9,0 +9.1 dduse 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->isSyncEvent()) {Sthis->handleSyncEvent(Sevent);$0namespace Jiminny.couse Jiminny Componel+ use Jiminny|Componenuse Jiminny Contractuse Psr\Log\LoggerInAsyncupdatedsevent->sevent->Sevent→f Daily - Platform • in 8mO All-In-One( Capture AreaC. Capture Previous Area- Capture Fullscreen• Capture WindowJ Scrolling CaptureU Self-TimerAa Capture Text (OCR)C Record Screen( Hide Desktop IconsD Open...$ Pin to the Screen…D Capture History...About CleanShot…Check for Updates...Settings...Quitwdso4-883TKTOTR100% LzP8• Tue 19 May 9:37:36+432 -159 8082|+2-1882ViewediGH : QueuePriorityEnum: :NORMAL,+9 -1 •0• Vieweduse Jiminny|Component\ES\Actions\TrackElasticSearchOperations;use Jiminny Component ts 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(),1* important:* Synchronous event should eventually be deprecated.* Instant write onerations are blockina and should be used soarinalv.* 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->icSvncFvent()) {|Sthis->handleSyncEvent(Sevent);...
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|