public class RaceConditionBug {
private volatile TaskState state = TaskState.PENDING;
public void processTaskWithBug(String taskId) {
if (state == TaskState.PENDING) {
Thread.sleep(100);
state = TaskState.RUNNING;
}
}
public void processTaskFixed(String taskId) {
synchronized (this) {
if (state == TaskState.PENDING) {
state = TaskState.RUNNING;
}
}
}
}
public class EventOrderingBug {
private BlockingQueue<StateEvent> eventQueue = new LinkedBlockingQueue<>();
private volatile TaskState state = TaskState.PENDING;
public void handleEventsWithBug() {
executor.submit(() -> {
StateEvent event1 = eventQueue.take();
processEvent(event1);
});
executor.submit(() -> {
StateEvent event2 = eventQueue.take();
processEvent(event2);
});
}
private final ExecutorService singleThreadExecutor =
Executors.newSingleThreadExecutor();
public void handleEventsFixed() {
singleThreadExecutor.submit(() -> {
while (true) {
StateEvent event = eventQueue.take();
processEvent(event);
}
});
}
}
public class StateTransitionBug {
private Lock stateLock = new ReentrantLock();
private TaskState state = TaskState.PENDING;
public void transitWithBug(TaskState newState) {
try {
stateLock.lock();
validateTransition(state, newState);
updateState(newState);
} finally {
stateLock.unlock();
}
}
@Transactional
public void transitFixed(TaskState newState) {
TaskEntity task = taskRepository.findById(taskId)
.orElseThrow(() -> new TaskNotFoundException(taskId));
validateTransition(task.getState(), newState);
task.setState(newState);
taskRepository.save(task);
publishStateChangeEvent(task);
}
}
public class NonIdempotentBug {
public void completeTaskWithBug(String taskId) {
TaskEntity task = taskRepository.findById(taskId).get();
task.setState(TaskState.COMPLETED);
task.setCompletionCount(task.getCompletionCount() + 1);
taskRepository.save(task);
}
public void completeTaskFixed(String taskId) {
taskRepository.updateTaskState(
taskId,
TaskState.RUNNING,
TaskState.COMPLETED
);
}
}
public class DistributedStateBug {
public void processDistributedTaskWithBug(String taskId) {
TaskEntity task = taskRepository.findById(taskId).get();
if (task.getState() == TaskState.PENDING) {
task.setState(TaskState.RUNNING);
taskRepository.save(task);
}
}
private final DistributedLock distributedLock;
public void processDistributedTaskFixed(String taskId) {
try {
if (distributedLock.tryLock(taskId, 5, TimeUnit.SECONDS)) {
try {
TaskEntity task = taskRepository.findById(taskId).get();
if (task.getState() == TaskState.PENDING) {
task.setState(TaskState.RUNNING);
taskRepository.save(task);
}
} finally {
distributedLock.unlock(taskId);
}
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new TaskProcessingException("Failed to acquire lock", e);
}
}
}
public class StateConsistencyBug {
public void updateRelatedStatesWithBug(String taskId) {
TaskEntity task = taskRepository.findById(taskId).get();
task.setState(TaskState.COMPLETED);
taskRepository.save(task);
List<SubTaskEntity> subTasks = subTaskRepository.findByParentId(taskId);
for (SubTaskEntity subTask : subTasks) {
subTask.setState(TaskState.COMPLETED);
subTaskRepository.save(subTask);
}
}
@Transactional
public void updateRelatedStatesFixed(String taskId) {
TaskEntity task = taskRepository.findById(taskId).get();
List<SubTaskEntity> subTasks = subTaskRepository.findByParentId(taskId);
task.setState(TaskState.COMPLETED);
taskRepository.save(task);
for (SubTaskEntity subTask : subTasks) {
subTask.setState(TaskState.COMPLETED);
subTaskRepository.save(subTask);
}
}
}