fix(infrared): add cutoff timestamp to failInterruptedLearning to prevent race with subsequent tasks

This commit is contained in:
2026-08-25 13:07:38 +08:00
parent a3812aae27
commit 2185e73f5e
9 changed files with 89 additions and 12 deletions
@@ -33,12 +33,13 @@ interface InfraredKeyRepository {
suspend fun deleteIfNotLearning(ref: InfraredKeyRef): DomainResult<Unit>
/**
* Atomically marks this profile's interrupted LEARNING keys as FAILED, clears the vendor
* error code, stores [INTERRUPTED_LEARNING_ERROR_DETAIL], and updates their timestamp.
* Atomically marks this profile's interrupted LEARNING keys created on or before [cutoffEpochMillis]
* as FAILED, clears the vendor error code, stores [INTERRUPTED_LEARNING_ERROR_DETAIL], and updates their timestamp.
*/
suspend fun failInterruptedLearning(
profileId: ProviderProfileId,
updatedAtEpochMillis: Long,
cutoffEpochMillis: Long = Long.MAX_VALUE,
updatedAtEpochMillis: Long = cutoffEpochMillis,
): DomainResult<Int>
}
@@ -159,13 +159,14 @@ class InMemoryInfraredKeyRepository : InfraredKeyRepository {
override suspend fun failInterruptedLearning(
profileId: ProviderProfileId,
cutoffEpochMillis: Long,
updatedAtEpochMillis: Long,
): DomainResult<Int> {
recoveryCalls += InfraredRecoveryCall(profileId, updatedAtEpochMillis)
recoveryError?.let { return DomainResult.Failure(it) }
var changed = 0
keys.replaceAll { _, key ->
if (key.profileId == profileId && key.status == InfraredKeyStatus.LEARNING) {
if (key.profileId == profileId && key.status == InfraredKeyStatus.LEARNING && key.createdAtEpochMillis <= cutoffEpochMillis) {
changed += 1
key.copy(
status = InfraredKeyStatus.FAILED,