Lines 100.00% 16 / 16
Methods 100.00% 3 / 3
Classes 100.00% 1 / 1
Name Lines Methods CRAP
 __construct 100.00% 1 / 1 100.00% 1 / 1 1
 planWorkerSlots 100.00% 11 / 11 100.00% 1 / 1 3
 resolvePoolSize 100.00% 4 / 4 100.00% 1 / 1 2
13final readonly class AppPlacement
14{
15    public function __construct(private int $autoPoolSize) {}
16
17    public function planWorkerSlots(AppDefinitionCollection $apps, StewartConfig $config): WorkerSlotCollection
18    {
19        $poolSize = $this->resolvePoolSize($apps, $config->workers);
20        $byWorker = [];
21        $next = 0;
22
23        foreach ($apps as $app) {
24            $workerId = $app->worker ?? $next++ % $poolSize;
25            $byWorker[$workerId][] = $app;
26        }
27
28        ksort($byWorker);
29        $slots = [];
30
31        foreach ($byWorker as $workerId => $pinned) {
32            $slots[] = new WorkerSlot(WorkerId::fromInt($workerId), AppDefinitionCollection::keyedByAppId($pinned));
33        }
34
35        return WorkerSlotCollection::fromList($slots);
36    }
37
38    private function resolvePoolSize(AppDefinitionCollection $apps, int $workers): int
39    {
40        if ($workers > 0) {
41            return $workers;
42        }
43
44        $highestPin = max([-1, ...$apps->mapToList(static fn(AppDefinition $app): int => $app->worker ?? -1)]);
45
46        return max(1, $this->autoPoolSize, $highestPin + 1);
47    }
48}