본문으로 건너뛰기

Backend Worker HTTP/1.1 Client

DNS, service URL, payload shape가 맞아 보이는데도 backend가 worker service 호출에 실패할 때 이 가이드를 사용합니다.

증상

  • chatbot-svc, grading-svc 또는 다른 Python worker로 가는 backend 호출이 즉시 실패합니다.
  • worker log에는 application validation error가 아니라 malformed 또는 invalid HTTP request가 보입니다.
  • 같은 endpoint가 curl 또는 단순 HTTP/1.1 client로는 동작합니다.
  • RestClient builder 또는 request factory를 변경한 뒤 실패가 나타납니다.

알려진 실패 이력

Commit표면실패 모드지속되는 수정
b8d0f278Chatbot workerJDK client가 plaintext에서 HTTP/2를 협상했고 uvicorn은 HTTP/1.1만 받았습니다.ChatbotClientHttpClient.Version.HTTP_1_1을 사용합니다.
9dcb463dOMR/report worker 호출shared RestClient wiring을 쓰는 worker 호출에도 같은 protocol risk가 있었습니다.RestClientConfigOmrServiceClient가 HTTP/1.1을 고정합니다.

현재 런타임 계약

backend는 Java RestClient를 쓰지만 worker service는 uvicorn 계열 HTTP/1.1 endpoint로 제공되는 Python/FastAPI process입니다. 따라서 backend client는 HTTP/1.1을 명시적으로 고정해야 합니다.

현재 소스 기준:

소스 경로계약
modules/ai/src/main/java/com/lumie/ai/adapter/out/external/ChatbotClient.javaHttpClient.Version.HTTP_1_1로 JDK HttpClient를 만듭니다.
modules/exam/src/main/java/com/lumie/exam/adapter/out/config/RestClientConfig.javashared exam RestClient.Builder가 HTTP/1.1 request factory를 사용합니다.
modules/exam/src/main/java/com/lumie/exam/adapter/out/external/OmrServiceClient.javaOMR call은 read timeout을 늘리되 HTTP/1.1은 유지합니다.

진단

  1. 실패 dependency가 RabbitMQ callback processing이 아니라 backend-to-worker HTTP call인지 확인합니다.
  2. worker log에서 invalid HTTP request parsing, early connection close, protocol mismatch 표현을 찾습니다.
  3. backend client source에서 request factory가 HTTP_1_1로 고정된 JDK HttpClient를 쓰는지 확인합니다.
  4. 호출이 여전히 X-Tenant-Slug를 전달하는지 확인합니다. protocol fix가 tenant propagation을 제거하면 안 됩니다.
  5. 같은 worker URL에 직접 HTTP/1.1 probe를 비교합니다.

소스 확인:

cd lumie-backend
rg -n "HTTP_1_1|JdkClientHttpRequestFactory|X-Tenant-Slug" \
modules/ai/src/main/java modules/exam/src/main/java

수정

명시적인 HTTP/1.1 JDK client에서 만든 request factory를 사용합니다.

HttpClient http11 = HttpClient.newBuilder()
.version(HttpClient.Version.HTTP_1_1)
.build();
RestClient client = restClientBuilder
.requestFactory(new JdkClientHttpRequestFactory(http11))
.build();

long-running image 또는 report call은 protocol pin을 유지하고 read timeout만 별도로 조정합니다. protocol negotiation을 다시 도입할 수 있는 default builder로 request factory를 바꾸지 않습니다.

검증 증거

  • worker log에 backend call에 대한 invalid HTTP request parsing이 더 이상 없습니다.
  • backend log가 application-level success 또는 validation failure까지 도달합니다.
  • request가 여전히 X-Tenant-Slug를 포함합니다.
  • OMR grading과 chatbot stream path가 각자의 timeout과 streaming behavior를 유지합니다.
  • 변경한 client를 source check 또는 test가 덮습니다.

예방

  • backend-to-worker HTTP client 설정을 worker compatibility contract의 일부로 취급합니다.
  • 새 worker client를 추가할 때 timeout을 조정하기 전에 HTTP/1.1 request factory pattern을 복사합니다.
  • uvicorn-backed service에 JDK default protocol negotiation을 사용하지 않습니다.
  • protocol fix를 payload, tenant, timeout fix와 분리해서 회귀 원인을 쉽게 찾을 수 있게 합니다.

관련 페이지