fix(shipping): replay immutable carrier facts without updates
This commit is contained in:
+1
-2
@@ -17,7 +17,6 @@ public interface CarrierScheduleExceptionFactMapper extends BaseMapper<CarrierSc
|
||||
#{value.providerStatus},#{value.exceptionCode},#{value.active},#{value.observedAt},
|
||||
#{value.locationCode},#{value.locationName},#{value.sourceReference},#{value.rawPayloadHash},
|
||||
CURRENT_TIMESTAMP(3))
|
||||
ON DUPLICATE KEY UPDATE id=id
|
||||
""")
|
||||
int insertIfAbsent(@Param("value") CarrierScheduleExceptionFactEntity value);
|
||||
int insertStrict(@Param("value") CarrierScheduleExceptionFactEntity value);
|
||||
}
|
||||
|
||||
+2
-3
@@ -20,14 +20,13 @@ public interface CarrierScheduleNodeFactMapper extends BaseMapper<CarrierSchedul
|
||||
#{value.standardNode},#{value.nodeSequence},#{value.observedAt},#{value.estimatedAt},#{value.actualAt},
|
||||
#{value.locationCode},#{value.locationName},#{value.sourceReference},#{value.rawPayloadHash},
|
||||
CURRENT_TIMESTAMP(3))
|
||||
ON DUPLICATE KEY UPDATE id=id
|
||||
""")
|
||||
int insertIgnore(@Param("value") CarrierScheduleNodeFactEntity value);
|
||||
int insertStrict(@Param("value") CarrierScheduleNodeFactEntity value);
|
||||
|
||||
@Select("SELECT * FROM fl_carrier_schedule_node_fact WHERE container_booking_id=#{containerBookingId} ORDER BY observed_at,id")
|
||||
List<CarrierScheduleNodeFactEntity> selectByContainer(@Param("containerBookingId") long containerBookingId);
|
||||
|
||||
@Select("SELECT * FROM fl_carrier_schedule_node_fact WHERE container_booking_id=#{containerBookingId} AND event_key=#{eventKey} LIMIT 1")
|
||||
@Select("SELECT * FROM fl_carrier_schedule_node_fact WHERE container_booking_id=#{containerBookingId} AND event_key=#{eventKey} LIMIT 1 FOR UPDATE")
|
||||
CarrierScheduleNodeFactEntity selectByContainerEvent(@Param("containerBookingId") long containerBookingId,
|
||||
@Param("eventKey") String eventKey);
|
||||
}
|
||||
|
||||
+27
-3
@@ -20,8 +20,10 @@ import com.baiyue.firstleg.portschedule.mapper.CarrierScheduleNodeFactMapper;
|
||||
import com.baiyue.firstleg.portschedule.mapper.CarrierScheduleExceptionFactMapper;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.stereotype.Repository;
|
||||
import org.springframework.dao.DuplicateKeyException;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Repository
|
||||
@@ -76,7 +78,20 @@ public class CarrierScheduleQueryRepository {
|
||||
.orderByAsc(CarrierScheduleNodeFactEntity::getObservedAt)
|
||||
.orderByAsc(CarrierScheduleNodeFactEntity::getId));
|
||||
}
|
||||
public boolean insertIfAbsent(CarrierScheduleNodeFactEntity value) { return nodes.insertIgnore(value) == 1; }
|
||||
public boolean insertIfAbsent(CarrierScheduleNodeFactEntity value) {
|
||||
try {
|
||||
return nodes.insertStrict(value) == 1;
|
||||
} catch (DuplicateKeyException duplicate) {
|
||||
// Current reads also see a concurrent committed winner under MySQL REPEATABLE READ.
|
||||
var idCollision = nodes.selectOne(new LambdaQueryWrapper<CarrierScheduleNodeFactEntity>()
|
||||
.eq(CarrierScheduleNodeFactEntity::getId, value.getId()).last("FOR UPDATE"));
|
||||
if (idCollision != null && (!Objects.equals(idCollision.getContainerBookingId(), value.getContainerBookingId())
|
||||
|| !Objects.equals(idCollision.getEventKey(), value.getEventKey()))) throw duplicate;
|
||||
if (nodeByContainer(value.getContainerBookingId(), value.getEventKey()) == null) throw duplicate;
|
||||
// The service retains the immutable fact comparison and rejects changed payloads.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
public CarrierScheduleNodeFactEntity node(long queryId, String eventKey) {
|
||||
return nodes.selectOne(new LambdaQueryWrapper<CarrierScheduleNodeFactEntity>()
|
||||
.eq(CarrierScheduleNodeFactEntity::getQueryId, queryId)
|
||||
@@ -101,12 +116,21 @@ public class CarrierScheduleQueryRepository {
|
||||
.orderByAsc(CarrierScheduleExceptionFactEntity::getId));
|
||||
}
|
||||
public boolean insertIfAbsent(CarrierScheduleExceptionFactEntity value) {
|
||||
return exceptions.insertIfAbsent(value) == 1;
|
||||
try {
|
||||
return exceptions.insertStrict(value) == 1;
|
||||
} catch (DuplicateKeyException duplicate) {
|
||||
var idCollision = exceptions.selectOne(new LambdaQueryWrapper<CarrierScheduleExceptionFactEntity>()
|
||||
.eq(CarrierScheduleExceptionFactEntity::getId, value.getId()).last("FOR UPDATE"));
|
||||
if (idCollision != null && (!Objects.equals(idCollision.getQueryId(), value.getQueryId())
|
||||
|| !Objects.equals(idCollision.getEventKey(), value.getEventKey()))) throw duplicate;
|
||||
if (exception(value.getQueryId(), value.getEventKey()) == null) throw duplicate;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
public CarrierScheduleExceptionFactEntity exception(long queryId, String eventKey) {
|
||||
return exceptions.selectOne(new LambdaQueryWrapper<CarrierScheduleExceptionFactEntity>()
|
||||
.eq(CarrierScheduleExceptionFactEntity::getQueryId, queryId)
|
||||
.eq(CarrierScheduleExceptionFactEntity::getEventKey, eventKey));
|
||||
.eq(CarrierScheduleExceptionFactEntity::getEventKey, eventKey).last("FOR UPDATE"));
|
||||
}
|
||||
public boolean claimOperation(Long queryId, long operatorId, String operation, String key, String hash) {
|
||||
return operations.claim(IdWorker.getId(), queryId, operatorId, operation, key, hash) == 1;
|
||||
|
||||
Reference in New Issue
Block a user