• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Freegle / Iznik / 28731

27 Jul 2026 05:40PM UTC coverage: 72.808% (-0.2%) from 73.051%
28731

push

circleci

web-flow
Merge pull request #1184 from Freegle/fix/new-area-remap-seeds-local-spatial

fix(digest): seed the batch-local spatial index before remapping a new area

13464 of 17673 branches covered (76.18%)

Branch coverage included in aggregate %.

25 of 30 new or added lines in 2 files covered. (83.33%)

179 existing lines in 7 files now uncovered.

141124 of 194650 relevant lines covered (72.5%)

38.12 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

50.0
/iznik-batch/app/Services/SpatialAdminService.php
1
<?php
2

3
namespace App\Services;
4

5
use Illuminate\Support\Facades\Http;
6
use Illuminate\Support\Facades\Log;
7

8
class SpatialAdminService
9
{
10
    private string $adminUrl;
11

12
    public function __construct()
23✔
13
    {
14
        $this->adminUrl = rtrim(config('freegle.spatial_admin_url', 'http://localhost:8195'), '/');
23✔
15
    }
16

17
    /**
18
     * Notify the spatial server to remove specific IDs from a dataset.
19
     *
20
     * Failures are logged as warnings and do not throw — the spatial server
21
     * will catch up on its next incremental sync or nightly rebuild.
22
     */
23
    public function removeItems(string $dataset, array $ids): void
×
24
    {
25
        if (empty($ids)) {
×
26
            return;
×
27
        }
28

29
        try {
30
            $response = Http::timeout(5)->post(
×
31
                "{$this->adminUrl}/v1/{$dataset}/remove",
×
32
                ['ids' => array_values($ids)]
×
33
            );
×
34

35
            if (!$response->successful()) {
×
36
                Log::warning("SpatialAdmin: remove {$dataset} HTTP {$response->status()}", [
×
37
                    'ids_count' => count($ids),
×
38
                ]);
×
39
            }
40
        } catch (\Throwable $e) {
×
41
            Log::warning("SpatialAdmin: remove {$dataset} failed: {$e->getMessage()}", [
×
42
                'ids_count' => count($ids),
×
43
            ]);
×
44
        }
45
    }
46

47
    /**
48
     * Ask the spatial server to fully rebuild a dataset's index from MySQL.
49
     *
50
     * Used after the WhatJobs sync RENAME-swaps the `jobs` table: the swap
51
     * drops rows for vanished/closed postings, but the spatial index's 5-min
52
     * delta only adds/updates (it never removes), so without an explicit
53
     * rebuild the KNN index keeps returning ids that are gone or now map to a
54
     * different posting until the nightly 03:00 rebuild — which is what made
55
     * job clicks stop converting to billable after the KNN cutover (#764).
56
     *
57
     * The server rebuild is asynchronous; this just kicks it off. Failures are
58
     * logged as warnings and do not throw — the periodic delta and the nightly
59
     * rebuild remain as backstops.
60
     */
61
    public function rebuildDataset(string $dataset): void
4✔
62
    {
63
        try {
64
            $response = Http::timeout(5)->post("{$this->adminUrl}/v1/{$dataset}/rebuild");
4✔
65

66
            if (!$response->successful()) {
3✔
67
                Log::warning("SpatialAdmin: rebuild {$dataset} HTTP {$response->status()}");
3✔
68
            }
69
        } catch (\Throwable $e) {
1✔
70
            Log::warning("SpatialAdmin: rebuild {$dataset} failed: {$e->getMessage()}");
1✔
71
        }
72
    }
73

74
    /**
75
     * Insert or replace specific items in a dataset's in-memory index straight
76
     * away, without waiting for the periodic delta sync.
77
     *
78
     * Needed because each container runs its OWN spatial-knn instance with an
79
     * independent in-memory index. A caller that must query the index it just
80
     * changed a row in (e.g. PostcodeRemapService remapping a brand-new area,
81
     * Discourse #9950) has to seed THIS process's instance first; the write-time
82
     * upsert done elsewhere lands on a different instance and never reaches here.
83
     *
84
     * $items: [['id' => int, 'wkt' => string, 'extra' => ['name' => ?, 'type' => ?]], ...].
85
     *
86
     * Failures are logged as warnings and do not throw — the periodic delta and
87
     * the nightly rebuild remain as backstops.
88
     */
89
    public function upsertItems(string $dataset, array $items): void
4✔
90
    {
91
        if (empty($items)) {
4✔
92
            return;
1✔
93
        }
94

95
        try {
96
            $response = Http::timeout(5)->post(
3✔
97
                "{$this->adminUrl}/v1/{$dataset}/upsert",
3✔
98
                ['items' => array_values($items)]
3✔
99
            );
3✔
100

101
            if (!$response->successful()) {
3✔
102
                Log::warning("SpatialAdmin: upsert {$dataset} HTTP {$response->status()}", [
3✔
103
                    'items_count' => count($items),
3✔
104
                ]);
3✔
105
            }
NEW
106
        } catch (\Throwable $e) {
×
NEW
107
            Log::warning("SpatialAdmin: upsert {$dataset} failed: {$e->getMessage()}", [
×
NEW
108
                'items_count' => count($items),
×
NEW
109
            ]);
×
110
        }
111
    }
112
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc