Refactored logic for Device becomes Online - #1683
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (2)
🚧 Files skipped from review as they are similar to previous changes (2)
📝 WalkthroughWalkthroughThe change records first-online events in MongoDB, processes pending records in tenant-scoped batches, dispatches matching online schedules, and marks successful records as dispatched through a scheduled, ShedLock-coordinated job. ChangesDevice-online dispatch workflow
Estimated code review effort: 4 (Complex) | ~45 minutes Sequence Diagram(s)sequenceDiagram
participant Machine
participant DeviceOnlineScheduleTriggerService
participant MachineFirstOnlineDispatchRepository
participant DeviceOnlineDispatchScheduler
participant DeviceOnlineDispatchService
participant ScriptScheduleRepository
Machine->>DeviceOnlineScheduleTriggerService: report online event
DeviceOnlineScheduleTriggerService->>MachineFirstOnlineDispatchRepository: save first-online record
DeviceOnlineDispatchScheduler->>DeviceOnlineDispatchService: processPending()
DeviceOnlineDispatchService->>MachineFirstOnlineDispatchRepository: read undispatched records
DeviceOnlineDispatchService->>ScriptScheduleRepository: load active DEVICE_ONLINE schedules
DeviceOnlineDispatchService->>MachineFirstOnlineDispatchRepository: mark successful records dispatched
Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches 💡 1📝 Generate docstrings 💡
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
…spatch' into feature/device-becomes-online-dispatch
…spatch' into feature/device-becomes-online-dispatch
There was a problem hiding this comment.
Actionable comments posted: 5
🧹 Nitpick comments (3)
openframe-data-mongo-sync/src/main/java/com/openframe/data/repository/device/MachineFirstOnlineDispatchRepository.java (1)
18-18: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick winBound the pending query in the database.
findByDispatchedAtIsNull()returns every pending record.DeviceOnlineDispatchService.processPendingthen discards all rows beyondbatchSizeon line 53. During a backlog, each tick loads the full pending set into memory and transfers it over the wire. Push the cap into the query instead.♻️ Proposed bounded query
- List<MachineFirstOnlineDispatch> findByDispatchedAtIsNull(); + List<MachineFirstOnlineDispatch> findByDispatchedAtIsNull(Pageable pageable);Then call it with
PageRequest.of(0, batchSize, Sort.by("firstSeenAt"))inDeviceOnlineDispatchService.processPending. Sorting byfirstSeenAtalso makes the drain order deterministic and prevents starvation of older rows.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@openframe-data-mongo-sync/src/main/java/com/openframe/data/repository/device/MachineFirstOnlineDispatchRepository.java` at line 18, Bound the pending-dispatch query instead of loading all records: update MachineFirstOnlineDispatchRepository.findByDispatchedAtIsNull to accept paging, then update DeviceOnlineDispatchService.processPending to call it with PageRequest.of(0, batchSize, Sort.by("firstSeenAt")). Preserve processing of only the requested page and remove any redundant in-memory truncation.openframe-client-core/src/test/java/com/openframe/client/service/DeviceOnlineDispatchServiceTest.java (1)
164-194: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winAdd coverage for a record with a null
tenantId.No test exercises a pending record with a null
tenantId. That input currently throwsNullPointerExceptioninsideCollectors.groupingByinDeviceOnlineDispatchService.processPendingand aborts the whole tick. Add the case after you apply the guard.💚 Proposed test
`@Test` `@DisplayName`("row with null tenantId → skipped, healthy rows still flush") void nullTenantRow_doesNotKillTheTick() { MachineFirstOnlineDispatch orphan = row("row-orphan", "m-orphan", null); MachineFirstOnlineDispatch good = row("row-good", "m-good", TENANT); when(dispatchRepository.findByDispatchedAtIsNull()).thenReturn(List.of(orphan, good)); stubTenantReads(TENANT, List.of(onlineMachine("m-good", TENANT)), List.of(), List.of()); service.processPending(); ArgumentCaptor<Collection<String>> ids = ArgumentCaptor.forClass(Collection.class); verify(dispatchRepository).markDispatchedIn(ids.capture(), any(Instant.class)); assertThat(ids.getValue()).containsExactly("row-good"); }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@openframe-client-core/src/test/java/com/openframe/client/service/DeviceOnlineDispatchServiceTest.java` around lines 164 - 194, Update DeviceOnlineDispatchService.processPending to skip pending records with a null tenantId before grouping by tenant, while continuing to process and mark valid tenant rows in the same tick. Add a test in DeviceOnlineDispatchServiceTest covering one null-tenant row and one healthy row, asserting only the healthy row is flushed.openframe-data-mongo-sync/src/main/java/com/openframe/data/repository/device/MachineRepository.java (1)
28-28: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueRemove the single-machine lookup from
MachineRepository.
findByTenantIdAndMachineId(String tenantId, String machineId)is only declared inMachineRepository; the dispatch/services flow usesfindByTenantIdAndMachineIdIn. Drop the unused method or wire it into the caller before keeping it.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@openframe-data-mongo-sync/src/main/java/com/openframe/data/repository/device/MachineRepository.java` at line 28, Remove the unused findByTenantIdAndMachineId method declaration from MachineRepository, since the dispatch/services flow uses findByTenantIdAndMachineIdIn instead. Do not alter the existing collection lookup.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In
`@openframe-client-core/src/main/java/com/openframe/client/scheduler/DeviceOnlineDispatchScheduler.java`:
- Around line 17-21: Update the scheduling flow around processPending and the
deviceOnlineDispatch SchedulerLock so concurrent replicas cannot process the
same pending rows: either configure lockAtMostFor above the worst-case batch
duration, or atomically claim each row before tenant reads and NATS dispatches,
handling claim conflicts with retries. Preserve the existing dispatch behavior
after rows are safely protected.
In
`@openframe-client-core/src/main/java/com/openframe/client/service/rmm/DeviceOnlineDispatchService.java`:
- Around line 111-119: Update the pending dispatch flow around machinesById
lookup and status validation so deleted or persistently OFFLINE machines receive
a terminal outcome and are removed from pending rather than retried
indefinitely. Use the existing dispatched marker or an appropriate
skipped/age-expiration field, with the configured cutoff if needed. Also make
the pending-record query order by firstSeenAt before applying the batch cap so
selection is deterministic.
- Around line 56-57: Update the batching flow in DeviceOnlineDispatchService to
filter out records with a null tenantId before the
groupingBy(MachineFirstOnlineDispatch::getTenantId) call, and log each discarded
record. Ensure these invalid records are drained without allowing grouping to
throw, while preserving grouping and per-tenant processing for valid records.
In
`@openframe-data-mongo-common/src/main/java/com/openframe/data/document/device/MachineFirstOnlineDispatch.java`:
- Around line 19-25: Ensure the unique tenant_machineId index declared on
MachineFirstOnlineDispatch is actually created at runtime or through a Mongo
migration. Add explicit startup index creation or a migration for the
machine_first_online_dispatch collection, preserving uniqueness across each
(tenantId, machineId) pair so DeviceOnlineScheduleTriggerService can rely on
DuplicateKeyException.
In
`@openframe-data-mongo-sync/src/main/java/com/openframe/data/repository/device/MachineFirstOnlineDispatchRepository.java`:
- Around line 20-22: Update the caller and success-tracking logic around
MachineFirstOnlineDispatchRepository.markDispatchedIn to treat its return value
as the modified-document count, not the matched ID count. Do not classify
already-dispatched IDs with the same dispatchedAt value as an update degradation
or omit them from successful tracking; preserve normal handling for genuinely
unmatched IDs.
---
Nitpick comments:
In
`@openframe-client-core/src/test/java/com/openframe/client/service/DeviceOnlineDispatchServiceTest.java`:
- Around line 164-194: Update DeviceOnlineDispatchService.processPending to skip
pending records with a null tenantId before grouping by tenant, while continuing
to process and mark valid tenant rows in the same tick. Add a test in
DeviceOnlineDispatchServiceTest covering one null-tenant row and one healthy
row, asserting only the healthy row is flushed.
In
`@openframe-data-mongo-sync/src/main/java/com/openframe/data/repository/device/MachineFirstOnlineDispatchRepository.java`:
- Line 18: Bound the pending-dispatch query instead of loading all records:
update MachineFirstOnlineDispatchRepository.findByDispatchedAtIsNull to accept
paging, then update DeviceOnlineDispatchService.processPending to call it with
PageRequest.of(0, batchSize, Sort.by("firstSeenAt")). Preserve processing of
only the requested page and remove any redundant in-memory truncation.
In
`@openframe-data-mongo-sync/src/main/java/com/openframe/data/repository/device/MachineRepository.java`:
- Line 28: Remove the unused findByTenantIdAndMachineId method declaration from
MachineRepository, since the dispatch/services flow uses
findByTenantIdAndMachineIdIn instead. Do not alter the existing collection
lookup.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 8905ecfa-6948-4111-bfbb-c453c272e687
📒 Files selected for processing (10)
openframe-client-core/src/main/java/com/openframe/client/scheduler/DeviceOnlineDispatchScheduler.javaopenframe-client-core/src/main/java/com/openframe/client/service/rmm/DeviceOnlineDispatchService.javaopenframe-client-core/src/main/java/com/openframe/client/service/rmm/DeviceOnlineScheduleTriggerService.javaopenframe-client-core/src/test/java/com/openframe/client/service/DeviceOnlineDispatchServiceTest.javaopenframe-client-core/src/test/java/com/openframe/client/service/DeviceOnlineScheduleTriggerServiceTest.javaopenframe-data-mongo-common/src/main/java/com/openframe/data/document/device/MachineFirstOnlineDispatch.javaopenframe-data-mongo-sync/src/main/java/com/openframe/data/repository/device/MachineFirstOnlineDispatchRepository.javaopenframe-data-mongo-sync/src/main/java/com/openframe/data/repository/device/MachineRepository.javaopenframe-data-mongo-sync/src/main/java/com/openframe/data/repository/rmm/ScriptScheduleMachineAssignedRepository.javaopenframe-data-mongo-sync/src/main/java/com/openframe/data/repository/rmm/ScriptScheduleRepository.java
| @Scheduled(fixedDelayString = "${openframe.rmm.device-online.dispatch.interval:60000}") | ||
| @SchedulerLock(name = "deviceOnlineDispatch", | ||
| lockAtMostFor = "${openframe.rmm.device-online.dispatch.lock-at-most-for:2m}", | ||
| lockAtLeastFor = "${openframe.rmm.device-online.dispatch.lock-at-least-for:10s}" | ||
| ) |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Confirm ShedLock is enabled and a LockProvider bean exists.
rg -nP --type=java -C3 'EnableSchedulerLock|LockProvider|EnableScheduling'
rg -n 'shedlock' --glob 'pom.xml' --glob 'build.gradle*' -iRepository: flamingo-stack/openframe-oss-lib
Length of output: 170
🏁 Script executed:
#!/bin/bash
set -u
echo "## candidate files"
git ls-files | rg 'DeviceOnlineDispatchScheduler|DeviceOnlineDispatchService|SchedulerLock|LockProvider|EnableSchedulerLock|EnableScheduling' || true
echo "## tracked Java files with annotations/classes of interest"
rg -n '`@Scheduled`|`@SchedulerLock`|EnableScheduling|EnableSchedulerLock|LockProvider' --type=java . || true
echo "## dependency/search for shedlock"
rg -n 'shedlock|shed-lock|net.javacrumbs|schedlock' -i --glob 'pom.xml' --glob 'build.gradle*' --glob 'settings.gradle*' --glob 'gradle.properties' . || trueRepository: flamingo-stack/openframe-oss-lib
Length of output: 7701
🏁 Script executed:
#!/bin/bash
set -u
echo "## DeviceOnlineDispatchScheduler.java"
cat -n openframe-client-core/src/main/java/com/openframe/client/scheduler/DeviceOnlineDispatchScheduler.java
echo "## DeviceOnlineDispatchService.java outline"
ast-grep outline openframe-client-core/src/main/java/com/openframe/client/service/rmm/DeviceOnlineDispatchService.java || true
echo "## DeviceOnlineDispatchService.java relevant content"
wc -l openframe-client-core/src/main/java/com/openframe/client/service/rmm/DeviceOnlineDispatchService.java
cat -n openframe-client-core/src/main/java/com/openframe/client/service/rmm/DeviceOnlineDispatchService.java
echo "## ShedLock client config"
cat -n openframe-client-core/src/main/java/com/openframe/client/config/ShedLockConfig.java
echo "## pom shedlock excerpts"
sed -n '40,70p' openframe-client-core/pom.xml | cat -nRepository: flamingo-stack/openframe-oss-lib
Length of output: 13044
Protect dispatch rows before cross-tenant work and size the lock above the batch duration.
processPending selects pending rows, reads per tenant, then marks rows dispatched only at the end. If a tenant’s reads plus NATS dispatches exceed lockAtMostFor (2 minutes), ShedLock releases the lock while later work still runs; a second replica can read the same pending rows and dispatch the same schedules twice. Extend lockAtMostFor above worst-case tick duration, or atomically mark each row as being processed before cross-tenant work and retry conflicts.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In
`@openframe-client-core/src/main/java/com/openframe/client/scheduler/DeviceOnlineDispatchScheduler.java`
around lines 17 - 21, Update the scheduling flow around processPending and the
deviceOnlineDispatch SchedulerLock so concurrent replicas cannot process the
same pending rows: either configure lockAtMostFor above the worst-case batch
duration, or atomically claim each row before tenant reads and NATS dispatches,
handling claim conflicts with retries. Preserve the existing dispatch behavior
after rows are safely protected.
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "## Scheduler"
cat -n openframe-client-core/src/main/java/com/openframe/client/scheduler/DeviceOnlineDispatchScheduler.java
echo "## Dispatch service structure"
ast-grep outline openframe-client-core/src/main/java/com/openframe/client/service/rmm/DeviceOnlineDispatchService.java --items all
echo "## Dispatch service"
cat -n openframe-client-core/src/main/java/com/openframe/client/service/rmm/DeviceOnlineDispatchService.java
echo "## Dispatch repository"
cat -n openframe-data-mongo-sync/src/main/java/com/openframe/data/repository/device/MachineFirstOnlineDispatchRepository.java
echo "## Relevant configuration and timeout/claim usages"
rg -n -i -C 3 \
'device-online\.dispatch|processPending\s*\(|markDispatchedIn\s*\(|dispatchedAt|lock-at-most-for|timeout|Duration|claim|processing' \
--glob '*.java' --glob '*.yml' --glob '*.yaml' --glob '*.properties' --glob 'pom.xml' .Length of output: 201413
🏁 Script executed:
#!/bin/bash
set -euo pipefail
for file in \
openframe-client-core/src/main/java/com/openframe/client/scheduler/DeviceOnlineDispatchScheduler.java \
openframe-client-core/src/main/java/com/openframe/client/service/rmm/DeviceOnlineDispatchService.java \
openframe-data-mongo-sync/src/main/java/com/openframe/data/repository/device/MachineFirstOnlineDispatchRepository.java \
openframe-data-mongo-common/src/main/java/com/openframe/data/document/device/MachineFirstOnlineDispatch.java
do
echo "## $file"
cat -n "$file"
done
echo "## Exact direct usages and declarations"
rg -n -C 4 \
'processPending\s*\(|markDispatchedIn\s*\(|findByDispatchedAtIsNull\s*\(|dispatch.*Schedule|schedule.*dispatch' \
openframe-client-core/src/main/java/com/openframe/client \
openframe-data-mongo-sync/src/main/java/com/openframe/data/repository/device \
openframe-api-lib/src/main/java/com/openframe/api/service/rmmLength of output: 25556
@kirill-567, yes. The finding is valid as a conditional concurrency risk.
processPending() reads up to 500 rows with dispatchedAt == null, dispatches schedules synchronously, and marks the rows only after all tenant work completes. The code has no processing claim and no bound that proves this work completes within the default two-minute lockAtMostFor.
If processing exceeds two minutes, another replica can acquire the ShedLock lock, read the same pending rows, and dispatch the same schedules.
This is not proof that normal executions exceed two minutes. It is a valid issue because the current code does not enforce that limit. The best fix is an atomic claim state with a lease and retry handling. Increasing lockAtMostFor is acceptable only if an operational maximum execution time is known and kept below that value.
You are interacting with an AI system.
| Machine machine = machinesById.get(row.getMachineId()); | ||
| if (machine == null) { | ||
| log.warn("DEVICE_ONLINE dispatch: machine gone before first fire, tenantId={} machineId={} — leaving pending", | ||
| row.getTenantId(), row.getMachineId()); | ||
| return Optional.empty(); | ||
| } | ||
| if (machine.getStatus() != DeviceStatus.ONLINE) { | ||
| return Optional.empty(); | ||
| } |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟠 Major | 🏗️ Heavy lift
Rows for deleted machines never drain.
If a machine is deleted, machinesById.get(...) returns null on every tick, and the record stays pending forever. The pending set then grows without bound, and the warning on lines 113-114 repeats on each tick.
The same effect occurs for a machine that stays OFFLINE. Combined with the unordered in-memory cap on line 53, permanently stuck records can occupy the batch and delay newer records indefinitely.
Add a terminal outcome for these records. Two options:
- Mark the record dispatched (or add a
skippedAt/attemptsfield) when the machine no longer exists. - Add an age cutoff so records older than a configured limit are marked and removed from the pending set.
Also, order the pending query by firstSeenAt so the batch selection is deterministic.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In
`@openframe-client-core/src/main/java/com/openframe/client/service/rmm/DeviceOnlineDispatchService.java`
around lines 111 - 119, Update the pending dispatch flow around machinesById
lookup and status validation so deleted or persistently OFFLINE machines receive
a terminal outcome and are removed from pending rather than retried
indefinitely. Use the existing dispatched marker or an appropriate
skipped/age-expiration field, with the configured cutoff if needed. Also make
the pending-record query order by firstSeenAt before applying the batch cap so
selection is deterministic.
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
service='openframe-client-core/src/main/java/com/openframe/client/service/rmm/DeviceOnlineDispatchService.java'
repo='openframe-data-mongo-sync/src/main/java/com/openframe/data/repository/device/MachineFirstOnlineDispatchRepository.java'
document='openframe-data-mongo-common/src/main/java/com/openframe/data/document/device/MachineFirstOnlineDispatch.java'
scheduler='openframe-client-core/src/main/java/com/openframe/client/scheduler/DeviceOnlineDispatchScheduler.java'
ast-grep outline "$service" --items all
printf '\n--- DeviceOnlineDispatchService ---\n'
cat -n "$service"
printf '\n--- MachineFirstOnlineDispatchRepository ---\n'
cat -n "$repo"
printf '\n--- MachineFirstOnlineDispatch ---\n'
cat -n "$document"
printf '\n--- DeviceOnlineDispatchScheduler ---\n'
cat -n "$scheduler"
printf '\n--- Pending-record lifecycle references ---\n'
rg -n -C 3 --glob '*.java' \
'MachineFirstOnlineDispatch|findByDispatchedAtIsNull|markDispatchedIn|dispatchedAt|firstSeenAt' \
openframe-client-core openframe-data-mongo-common openframe-data-mongo-syncLength of output: 132194
@kirill-567, partially valid.
The deleted-machine case is valid. processOne() leaves a missing machine pending, and no other code clears that record. The existing test also expects this behavior. Those records can remain pending forever.
The deterministic batching concern is also valid. findByDispatchedAtIsNull() has no sort, but processPending() applies limit(batchSize). MongoDB does not guarantee a useful order without an explicit sort. Stuck records can therefore delay other pending records.
The offline-machine part needs refinement. A machine can be offline only because the scheduler runs after the device disconnects. It must remain pending in that case. A terminal outcome should apply only after an explicit policy, such as a configured maximum age or retry limit.
I would keep the finding, but scope the required change to:
- Add a deterministic pending query, ordered by
firstSeenAtand optionally_idas a tie-breaker. - Add a terminal state for missing machines.
- If the product requires bounded retries for offline machines, add a configured age or retry cutoff with a separate
skippedAt/reason field.
🐇🔎
You are interacting with an AI system.
| @CompoundIndex( | ||
| name = "tenant_machineId", | ||
| def = "{'tenantId': 1, 'machineId': 1}", | ||
| unique = true) | ||
| @CompoundIndex( | ||
| name = "dispatchedAt_pending", | ||
| def = "{'dispatchedAt': 1}") |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟠 Major | 🏗️ Heavy lift
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Check for Mongo auto index creation config and index migrations.
rg -n --glob '*.{yml,yaml,properties}' 'auto-index-creation|autoIndexCreation'
rg -n 'MongoMappingContext|setAutoIndexCreation|IndexOperations|ensureIndex|createIndex' --glob '*.java'
fd -i 'mongock|migration|changelog|changeunit' -t d -t f | head -50Repository: flamingo-stack/openframe-oss-lib
Length of output: 170
🏁 Script executed:
#!/bin/bash
set -u
echo "Repo files of interest:"
git ls-files | rg '(^|/)(Application|application|application-docker|application-local|application-dev|application-test|application-prod)\.(yml|yaml|properties)$|^(pom\.xml|build\.(gradle|kts))$|^openframe-data-mongo-common/src/main/java/com/openframe/data/document/device/MachineFirstOnlineDispatch\.java$' || true
echo
echo "MachineFirstOnlineDispatch.java outline:"
ast-grep outline openframe-data-mongo-common/src/main/java/com/openframe/data/document/device/MachineFirstOnlineDispatch.java 2>/dev/null || true
echo
echo "MachineFirstOnlineDispatch.java relevant lines:"
cat -n openframe-data-mongo-common/src/main/java/com/openframe/data/document/device/MachineFirstOnlineDispatch.java | sed -n '1,100p'
echo
echo "Search mongo index creation patterns (all Java):"
rg -n --glob '*.java' 'setAutoIndexCreation|IndexOperations|ensureIndex|createIndex|MongoMappingContext|DuplicateKeyException|`@CompoundIndex`|`@CompoundIndexes`' . || true
echo
echo "Search auto index config (all tracked files):"
rg -n 'auto[-_]?index|autoIndexCreation|spring\.data\.mongodb|mongo' --glob '*.{yml,yaml,properties,json,xml,gradle,kts}' . || true
echo
echo "Dependency mentions for Spring Boot / Spring Data MongoDB / Mongo migrations:"
rg -n 'Spring Boot|spring-boot|spring-data-mongodb|MongoDB|Mongoock|mongoock|Mongock|mongo:|mongodb:' --glob '*.{xml,yml,yaml,properties,gradle,kts,md}' . || trueRepository: flamingo-stack/openframe-oss-lib
Length of output: 50389
Ensure machine_first_online_dispatch.tenant_machineId exists.
DeviceOnlineScheduleTriggerService uses DuplicateKeyException to prevent duplicate dispatch records for each (tenantId, machineId) pair. The collection currently has no ensureIndex/Mongo migration or auto-index setting, so add a migration or explicit startup index creation for this unique index.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In
`@openframe-data-mongo-common/src/main/java/com/openframe/data/document/device/MachineFirstOnlineDispatch.java`
around lines 19 - 25, Ensure the unique tenant_machineId index declared on
MachineFirstOnlineDispatch is actually created at runtime or through a Mongo
migration. Add explicit startup index creation or a migration for the
machine_first_online_dispatch collection, preserving uniqueness across each
(tenantId, machineId) pair so DeviceOnlineScheduleTriggerService can rely on
DuplicateKeyException.
…spatch' into feature/device-becomes-online-dispatch
Summary by CodeRabbit