경쟁 상태란 두 개 이상의 프로세스나 스레드가 공유 자원에 동시에 접근하여 읽거나 쓰려고 할 때, 접근 순서에 따라 실행 결과가 달라지는 현상입니다.
다음은 이번에 OnPyRunner를 개선하면서 발생한 예시입니다. 처음에 제가 의도하고, 작성한 코드의 흐름은 다음과 같습니다.
| API Server | Worker |
|---|---|
| 1. 큐에 작업 추가 | |
| 2. Redis에 PENDING 기록 | |
| 3. 큐에서 작업 꺼내기 | |
| 4. Redis에 RUNNING 기록 |
여기서 저는 당연히 코드가 의도한 대로 Redis에는 항상 PENDING 후에 RUNNING이 기록될 것이라고 생각했습니다.
하지만 아래의 경우는 아닙니다.
| API Server | Worker |
|---|---|
| 1. 큐에 작업 추가 | |
| 2. 큐에서 작업 꺼내기 | |
| 3. Redis에 RUNNING 기록 | |
| 4. Redis에 PENDING 기록 |
제가 놓친 부분은 서로 다른 프로세스가 함께 돌아갈 때, 그 순서를 보장하도록 명시하지 않았다는 것입니다.
이 문제를 해결하기 위해 가장 간단한 방법은 그냥 순서를 바꾸는 것입니다.
API Server가 Redis에 PENDING을 먼저 기록하게 하고, 그 후 큐에 작업을 추가하는 것으로 해결할 수 있습니다.
| API Server | Worker |
|---|---|
| 1. Redis에 PENDING 기록 | |
| 2. 큐에 작업 추가 | |
| 3. 큐에서 작업 꺼내기 | |
| 4. Redis에 RUNNING 기록 |
물건이 들어와야 나간다는 Queue의 특성을 이용하는 것입니다.
문제는 해결하였습니다.
하지만 같은 실수를 반복하지 않으려면 어떤식으로 생각해야할까요?
데이터를 바라볼 때 누가 그 데이터를 바꾸는지를 보아야 합니다.
Redis에 Job의 State를 기록하는 주체는 API Server와 Worker가 있습니다. 서로가 서로의 작업에 끼어들어 접근 순서가 달라질 때, 그 때도 데이터 상태의 순서(PENDING 다음 RUNNING이 오는 순서)가 역전되지 않는지를 생각해야 합니다.
나아가서 결정론적인 테스트를 통해 상태가 역전 흐름이 발생하는지를 검증하려면 어떻게 해야할까요?
아마 다음 이야기가 될 것 같습니다.