[Feat] analysis async를 MQ worker 구조로 전환하고 worker 상태 메타데이터를 확장 (#110)#116
Conversation
|
Warning Review limit reached
Next review available in: 49 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (13)
📝 WalkthroughWalkthroughIntroduces RabbitMQ-backed async worker flows for analysis and job posting, with richer task metadata, internal worker endpoints, scoped task lookup, and queue/publisher configuration updates. Also adds payment confirmation timeout handling that can roll a processing payment back to pending. ChangesAsync worker pipeline
Payment timeout rollback
Estimated code review effort: 5 (Critical) | ~120 minutes Sequence Diagram(s)sequenceDiagram
participant Client
participant AsyncFacadeService
participant AsyncTaskService
participant AsyncProcessor
participant RabbitPublishSupport
participant RabbitMQ
participant Worker
participant WorkerInternalController
participant WorkerBridgeService
Client->>AsyncFacadeService: submit(user, request)
AsyncFacadeService->>AsyncTaskService: createPendingTask(userId, maxRetryCount)
AsyncFacadeService->>AsyncProcessor: process(taskId, userId, mockApplyId, maxRetryCount)
AsyncProcessor->>RabbitPublishSupport: publish(task message)
RabbitPublishSupport->>RabbitMQ: convertAndSend + confirm wait
RabbitMQ-->>Worker: deliver task message
Worker->>WorkerInternalController: markRunning / getContext / completeTask
WorkerInternalController->>WorkerBridgeService: delegate validated request
WorkerBridgeService->>AsyncTaskService: update task state or fetch status
sequenceDiagram
participant Client
participant PaymentService
participant TossPaymentClient
participant PaymentTransactionService
participant Payment
Client->>PaymentService: confirm(...)
PaymentService->>TossPaymentClient: confirm(...)
TossPaymentClient-->>PaymentService: GeneralException(EXTERNAL_SERVICE_TIMEOUT)
PaymentService->>PaymentTransactionService: rollbackConfirmationToPending(...)
PaymentTransactionService->>Payment: resetToPending()
PaymentService-->>Client: rethrow GeneralException
Possibly related PRs
Suggested labels: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 7
🧹 Nitpick comments (4)
src/main/java/com/jobdri/jobdri_api/global/config/RabbitMqConfig.java (1)
52-77: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winAnalysis queue/DLQ/binding beans duplicate the job-posting pattern verbatim.
analysisQueue,analysisDeadLetterQueue, andanalysisBindingmirrorjobPostingIngestQueue/jobPostingIngestDeadLetterQueue/jobPostingIngestBindingstructurally. As more worker types are added (per the PR stack outline), this duplication will keep growing. Consider extracting a small factory helper (e.g.,buildDurableQueueWithDlq(name, dlqName)) to construct queue+DLQ pairs consistently.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/main/java/com/jobdri/jobdri_api/global/config/RabbitMqConfig.java` around lines 52 - 77, The analysis queue, dead-letter queue, and binding setup in RabbitMqConfig duplicates the job-posting worker pattern, so refactor the repeated queue/binding creation into a shared helper or factory method. Use the existing bean methods such as analysisQueue, analysisDeadLetterQueue, and analysisBinding alongside the jobPostingIngest* equivalents to centralize durable queue-with-DLQ construction and reuse the same binding setup for future worker types.src/main/java/com/jobdri/jobdri_api/domain/analysis/controller/AnalysisWorkerInternalController.java (1)
36-104: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winRepeated API-key validation boilerplate across every endpoint.
Each handler manually calls
internalApiKeyValidator.validate(internalApiKey)first. Centralizing this via aHandlerInterceptor/filter scoped to/api/internal/worker/**would remove the duplication and eliminate the risk of a future endpoint being added without the check.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/main/java/com/jobdri/jobdri_api/domain/analysis/controller/AnalysisWorkerInternalController.java` around lines 36 - 104, The Internal API key check is duplicated in every handler of AnalysisWorkerInternalController, which makes it easy to miss on future endpoints. Move the validation out of markRunning, markRetry, failTask, getContext, completeTask, and getTask into a centralized HandlerInterceptor or filter scoped to the internal worker routes, and keep the controller methods focused on request handling only.src/main/java/com/jobdri/jobdri_api/domain/analysis/service/AnalysisTaskMessagePublisher.java (2)
12-20: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueConstructor vs. field injection mismatch.
rabbitTemplateis constructor-injected via Lombok's@RequiredArgsConstructor, whileexchange/routingKeyrely on@Valuefield injection on non-final fields. This is harmless in production (Spring populates both), but complicates unit testing — instantiating via the generated constructor leavesexchange/routingKeynull unless a full Spring context is used or values are set via reflection.♻️ Optional refactor: constructor-inject the values
- private final RabbitTemplate rabbitTemplate; - - `@Value`("${app.worker.analysis.exchange:jobdri.worker.exchange}") - private String exchange; - - `@Value`("${app.worker.analysis.routing-key:analysis.execute}") - private String routingKey; + private final RabbitTemplate rabbitTemplate; + + private final String exchange; + private final String routingKey; + + public AnalysisTaskMessagePublisher( + RabbitTemplate rabbitTemplate, + `@Value`("${app.worker.analysis.exchange:jobdri.worker.exchange}") String exchange, + `@Value`("${app.worker.analysis.routing-key:analysis.execute}") String routingKey + ) { + this.rabbitTemplate = rabbitTemplate; + this.exchange = exchange; + this.routingKey = routingKey; + }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/main/java/com/jobdri/jobdri_api/domain/analysis/service/AnalysisTaskMessagePublisher.java` around lines 12 - 20, The AnalysisTaskMessagePublisher setup mixes constructor injection for rabbitTemplate with field injection for exchange and routingKey, which leaves those values unset when using the Lombok-generated constructor in tests. Refactor the class to inject exchange and routingKey through the constructor as well, aligning them with rabbitTemplate in the AnalysisTaskMessagePublisher constructor/@RequiredArgsConstructor usage so the publisher can be instantiated cleanly without Spring field injection or reflection.
22-30: 🩺 Stability & Availability | 🔵 Trivial | 🏗️ Heavy liftNo publisher confirms/returns — message loss is silent.
By default, Spring AMQP publishing is fire-and-forget: "Publishing messages is an asynchronous mechanism and, by default, messages that cannot be routed are dropped by RabbitMQ." If the exchange/queue binding is misconfigured or the broker nacks the message,
publish()returns normally with no error, leaving the task stuck (no worker will ever pick it up) with nothing surfacing the failure.Consider enabling publisher confirms/returns on the connection factory (via
RabbitMqConfig, layer 6) and wiring aConfirmCallback/ReturnsCallbackhere to detect and react to failed publishes (e.g., mark the task failed).🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/main/java/com/jobdri/jobdri_api/domain/analysis/service/AnalysisTaskMessagePublisher.java` around lines 22 - 30, Add publish-failure handling to AnalysisTaskMessagePublisher.publish so silent RabbitMQ drops/nacks are detected. Wire publisher confirms and returns through RabbitMqConfig/connection factory, then register a ConfirmCallback and ReturnsCallback on rabbitTemplate to catch broker nacks or unroutable messages. In publish(), use the existing exchange/routingKey flow but ensure failed sends are surfaced and can trigger task-failure handling instead of returning normally.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In
`@src/main/java/com/jobdri/jobdri_api/domain/analysis/dto/worker/AnalysisWorkerCompleteRequest.java`:
- Around line 12-14: The `AnalysisWorkerCompleteRequest` still carries
`openAiRequestId` even though it is not used in the success flow. Either remove
`openAiRequestId` from `AnalysisWorkerCompleteRequest` if it should not be
retained, or thread it through `AnalysisAsyncTask` and the completion path so it
is persisted alongside `workerId` and `queueLatencyMillis`.
In
`@src/main/java/com/jobdri/jobdri_api/domain/analysis/dto/worker/AnalysisWorkerFailureRequest.java`:
- Around line 8-15: The failure request already carries observability fields,
but `failTask(...)` and `markFailed` are not persisting them, so failure records
lose attribution data. Update the failure path to accept and forward
`AnalysisWorkerFailureRequest.workerId`, `queueLatencyMillis`, and
`openAiRequestId` into `failTask(...)` and then through `markFailed`, ensuring
the failure entity/logging captures these values instead of dropping them.
In
`@src/main/java/com/jobdri/jobdri_api/domain/analysis/entity/AnalysisAsyncTask.java`:
- Around line 129-145: `markRetryScheduled` in `AnalysisAsyncTask` does not
enforce the stored `maxRetryCount`, so retries can be rescheduled indefinitely.
Update `markRetryScheduled(FailureReason, String, int)` to compare the incoming
`retryCount` against `maxRetryCount` and, when the cap is reached or exceeded,
transition the task to `FAILED` instead of `PENDING` (reuse `markFailed`/the
same status/message fields as appropriate). Keep the retry-state logic
self-contained in `AnalysisAsyncTask` so callers like `AnalysisAsyncTaskService`
and `AnalysisWorkerBridgeService` cannot accidentally bypass the limit.
In
`@src/main/java/com/jobdri/jobdri_api/domain/analysis/service/AnalysisAsyncProcessor.java`:
- Around line 13-16: The publish path in AnalysisAsyncProcessor.process can fail
after credit has already been reserved, leaving the user charged even though no
task was queued. Update the flow around
analysisTaskMessagePublisher.publish(...) to catch synchronous publish failures
and trigger the same credit release/refund logic used elsewhere in
createAndProcessTask, using the existing AnalysisAsyncProcessor and task/credit
service methods to keep the reservation state consistent.
In
`@src/main/java/com/jobdri/jobdri_api/domain/analysis/service/AnalysisWorkerBridgeService.java`:
- Around line 33-39: `markRunning` and `markRetry` in
`AnalysisWorkerBridgeService` currently delegate straight to
`AnalysisAsyncTaskService` and can reopen finished tasks by calling
`markRunning` or `markRetryScheduled` without checking terminal states. Add the
same terminal-state protection used by `failTask` before delegating, so tasks
already in `SUCCEEDED` or `FAILED` are not moved back to `RUNNING` or `PENDING`.
Update the guard in the bridge service and ensure the corresponding
`AnalysisAsyncTask` transition methods respect the finished-state check
consistently.
- Around line 79-100: `completeTask` currently trusts `request.userId()` and
`request.mockApplyId()` instead of verifying them against the persisted
`AnalysisAsyncTask` identity. Add the same user/mockApply equality guard used in
`getContext` near the start of `completeTask`, before
`prepareAnalysisExecution`, `finalizeAnalysis`, and `confirmAnalysisCredit`, and
fail fast with the existing error pattern if they do not match. Use
`AnalysisWorkerBridgeService`, `getTask`, and `completeTask` to locate the flow
and ensure the task’s stored user/mockApply pair is the only one allowed to
complete it.
In `@src/main/java/com/jobdri/jobdri_api/global/config/RabbitMqConfig.java`:
- Around line 18-23: The worker exchange is configured separately from the
publishers, which can cause `AnalysisTaskMessagePublisher` and
`JobPostingTaskMessagePublisher` to send messages to exchanges that
`RabbitMqConfig.workerExchange` does not bind to. Update the publisher wiring to
inject and reuse the shared `workerExchange` bean (or its resolved name) instead
of reading independent publisher exchange properties, so both publishers always
target the same exchange as the queue bindings.
---
Nitpick comments:
In
`@src/main/java/com/jobdri/jobdri_api/domain/analysis/controller/AnalysisWorkerInternalController.java`:
- Around line 36-104: The Internal API key check is duplicated in every handler
of AnalysisWorkerInternalController, which makes it easy to miss on future
endpoints. Move the validation out of markRunning, markRetry, failTask,
getContext, completeTask, and getTask into a centralized HandlerInterceptor or
filter scoped to the internal worker routes, and keep the controller methods
focused on request handling only.
In
`@src/main/java/com/jobdri/jobdri_api/domain/analysis/service/AnalysisTaskMessagePublisher.java`:
- Around line 12-20: The AnalysisTaskMessagePublisher setup mixes constructor
injection for rabbitTemplate with field injection for exchange and routingKey,
which leaves those values unset when using the Lombok-generated constructor in
tests. Refactor the class to inject exchange and routingKey through the
constructor as well, aligning them with rabbitTemplate in the
AnalysisTaskMessagePublisher constructor/@RequiredArgsConstructor usage so the
publisher can be instantiated cleanly without Spring field injection or
reflection.
- Around line 22-30: Add publish-failure handling to
AnalysisTaskMessagePublisher.publish so silent RabbitMQ drops/nacks are
detected. Wire publisher confirms and returns through RabbitMqConfig/connection
factory, then register a ConfirmCallback and ReturnsCallback on rabbitTemplate
to catch broker nacks or unroutable messages. In publish(), use the existing
exchange/routingKey flow but ensure failed sends are surfaced and can trigger
task-failure handling instead of returning normally.
In `@src/main/java/com/jobdri/jobdri_api/global/config/RabbitMqConfig.java`:
- Around line 52-77: The analysis queue, dead-letter queue, and binding setup in
RabbitMqConfig duplicates the job-posting worker pattern, so refactor the
repeated queue/binding creation into a shared helper or factory method. Use the
existing bean methods such as analysisQueue, analysisDeadLetterQueue, and
analysisBinding alongside the jobPostingIngest* equivalents to centralize
durable queue-with-DLQ construction and reuse the same binding setup for future
worker types.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 6dca01d3-e631-4e16-9c2c-1319a67ef89b
📒 Files selected for processing (22)
.env.example.env.production.exampleops/db/migrations/20260704_analysis_async_tasks_worker_metadata.sqlsrc/main/java/com/jobdri/jobdri_api/domain/analysis/controller/AnalysisWorkerInternalController.javasrc/main/java/com/jobdri/jobdri_api/domain/analysis/dto/response/AnalysisAsyncStatusResponse.javasrc/main/java/com/jobdri/jobdri_api/domain/analysis/dto/worker/AnalysisTaskMessage.javasrc/main/java/com/jobdri/jobdri_api/domain/analysis/dto/worker/AnalysisWorkerCompleteRequest.javasrc/main/java/com/jobdri/jobdri_api/domain/analysis/dto/worker/AnalysisWorkerContextRequest.javasrc/main/java/com/jobdri/jobdri_api/domain/analysis/dto/worker/AnalysisWorkerContextResponse.javasrc/main/java/com/jobdri/jobdri_api/domain/analysis/dto/worker/AnalysisWorkerFailureRequest.javasrc/main/java/com/jobdri/jobdri_api/domain/analysis/dto/worker/AnalysisWorkerRetryRequest.javasrc/main/java/com/jobdri/jobdri_api/domain/analysis/dto/worker/AnalysisWorkerRunningRequest.javasrc/main/java/com/jobdri/jobdri_api/domain/analysis/entity/AnalysisAsyncTask.javasrc/main/java/com/jobdri/jobdri_api/domain/analysis/service/AnalysisAsyncFacadeService.javasrc/main/java/com/jobdri/jobdri_api/domain/analysis/service/AnalysisAsyncProcessor.javasrc/main/java/com/jobdri/jobdri_api/domain/analysis/service/AnalysisAsyncTaskService.javasrc/main/java/com/jobdri/jobdri_api/domain/analysis/service/AnalysisTaskMessagePublisher.javasrc/main/java/com/jobdri/jobdri_api/domain/analysis/service/AnalysisWorkerBridgeService.javasrc/main/java/com/jobdri/jobdri_api/global/config/RabbitMqConfig.javasrc/main/resources/application-dev.yamlsrc/main/resources/application-prod.yamlsrc/test/java/com/jobdri/jobdri_api/domain/analysis/service/AnalysisAsyncFacadeServiceTest.java
| public record AnalysisWorkerFailureRequest( | ||
| @NotBlank String errorMessage, | ||
| @NotNull FailureReason failureReason, | ||
| @Min(0) int retryCount, | ||
| @NotBlank String workerId, | ||
| Long queueLatencyMillis, | ||
| String openAiRequestId | ||
| ) { |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Check whether the bridge/task service's failTask/markFailed persist worker metadata anywhere else
rg -n -A10 'void failTask' src/main/java/com/jobdri/jobdri_api/domain/analysis/service/AnalysisWorkerBridgeService.java
rg -n -A10 'markFailed' src/main/java/com/jobdri/jobdri_api/domain/analysis/service/AnalysisAsyncTaskService.javaRepository: JobDri-Developer/BackEnd
Length of output: 1171
Pass the telemetry fields through the failure path. workerId, queueLatencyMillis, and openAiRequestId are validated on AnalysisWorkerFailureRequest but dropped by failTask(...), so failure records never get those observability fields. Thread them into failTask/markFailed so failures can be attributed.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In
`@src/main/java/com/jobdri/jobdri_api/domain/analysis/dto/worker/AnalysisWorkerFailureRequest.java`
around lines 8 - 15, The failure request already carries observability fields,
but `failTask(...)` and `markFailed` are not persisting them, so failure records
lose attribution data. Update the failure path to accept and forward
`AnalysisWorkerFailureRequest.workerId`, `queueLatencyMillis`, and
`openAiRequestId` into `failTask(...)` and then through `markFailed`, ensuring
the failure entity/logging captures these values instead of dropping them.
| public void process(String taskId, Long userId, Long mockApplyId, String creditReferenceId, int maxRetryCount) { | ||
| analysisTaskMessagePublisher.publish( | ||
| AnalysisTaskMessage.of(taskId, userId, mockApplyId, creditReferenceId, maxRetryCount) | ||
| ); |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Inspect full facade catch block for credit release handling
rg -n -B5 -A20 'catch \(RuntimeException e\)' src/main/java/com/jobdri/jobdri_api/domain/analysis/service/AnalysisAsyncFacadeService.javaRepository: JobDri-Developer/BackEnd
Length of output: 1200
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== Facade =="
sed -n '1,140p' src/main/java/com/jobdri/jobdri_api/domain/analysis/service/AnalysisAsyncFacadeService.java
echo
echo "== Processor =="
sed -n '1,120p' src/main/java/com/jobdri/jobdri_api/domain/analysis/service/AnalysisAsyncProcessor.java
echo
echo "== Search for credit release/refund paths =="
rg -n "release|refund|reserveAnalysisCredit|deleteTask\\(" src/main/java/com/jobdri/jobdri_api/domain/analysis -SRepository: JobDri-Developer/BackEnd
Length of output: 8551
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== AnalysisAsyncTaskService =="
sed -n '1,140p' src/main/java/com/jobdri/jobdri_api/domain/analysis/service/AnalysisAsyncTaskService.java
echo
echo "== AnalysisService =="
sed -n '1,160p' src/main/java/com/jobdri/jobdri_api/domain/analysis/service/AnalysisService.java
echo
echo "== AnalysisWorkerBridgeService (credit release path) =="
sed -n '1,180p' src/main/java/com/jobdri/jobdri_api/domain/analysis/service/AnalysisWorkerBridgeService.javaRepository: JobDri-Developer/BackEnd
Length of output: 19024
Release reserved credit when message publish fails. createAndProcessTask() only deletes the task in its catch, so a synchronous failure from analysisTaskMessagePublisher.publish(...) after reserveAnalysisCredit(...) leaves the user's credit consumed even though no job was queued. Releasing/refunding the credit here would close that gap.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In
`@src/main/java/com/jobdri/jobdri_api/domain/analysis/service/AnalysisAsyncProcessor.java`
around lines 13 - 16, The publish path in AnalysisAsyncProcessor.process can
fail after credit has already been reserved, leaving the user charged even
though no task was queued. Update the flow around
analysisTaskMessagePublisher.publish(...) to catch synchronous publish failures
and trigger the same credit release/refund logic used elsewhere in
createAndProcessTask, using the existing AnalysisAsyncProcessor and task/credit
service methods to keep the reservation state consistent.
| @Bean | ||
| public DirectExchange workerExchange( | ||
| @Value("${app.worker.job-posting.exchange:jobdri.worker.exchange}") String exchangeName | ||
| @Value("${app.worker.exchange:jobdri.worker.exchange}") String exchangeName | ||
| ) { | ||
| return new DirectExchange(exchangeName, true, false); | ||
| } |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf 'Repo root: '; pwd
echo
# Locate relevant files
fd -a 'RabbitMqConfig.java|AnalysisTaskMessagePublisher.java|JobPostingIngestMessagePublisher.java|application.yml|application.yaml|application-*.yml|application-*.yaml' .
# Show AST outlines for the likely files if present
for f in src/main/java/com/jobdri/jobdri_api/global/config/RabbitMqConfig.java \
src/main/java/com/jobdri/jobdri_api/global/messaging/AnalysisTaskMessagePublisher.java \
src/main/java/com/jobdri/jobdri_api/global/messaging/JobPostingIngestMessagePublisher.java \
src/main/resources/application.yml \
src/main/resources/application.yaml; do
if [ -f "$f" ]; then
echo "=== OUTLINE: $f ==="
ast-grep outline "$f" --view expanded || true
echo
fi
done
# Print line-numbered snippets for relevant Java files
for f in src/main/java/com/jobdri/jobdri_api/global/config/RabbitMqConfig.java \
src/main/java/com/jobdri/jobdri_api/global/messaging/AnalysisTaskMessagePublisher.java \
src/main/java/com/jobdri/jobdri_api/global/messaging/JobPostingIngestMessagePublisher.java; do
if [ -f "$f" ]; then
echo "=== FILE: $f ==="
wc -l "$f"
cat -n "$f" | sed -n '1,220p'
echo
fi
done
# Print relevant app config snippets
for f in src/main/resources/application.yml src/main/resources/application.yaml; do
if [ -f "$f" ]; then
echo "=== FILE: $f ==="
wc -l "$f"
cat -n "$f" | sed -n '1,260p'
echo
fi
doneRepository: JobDri-Developer/BackEnd
Length of output: 5138
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Quick focused search for the exchange properties and bindings.
rg -n --hidden --no-ignore-vcs \
'app\.worker(\.analysis|\.job-posting|\.exchange)|workerExchange|analysisBinding|jobPostingIngestBinding|AnalysisTaskMessagePublisher|JobPostingIngestMessagePublisher' \
src/main/java src/main/resourcesRepository: JobDri-Developer/BackEnd
Length of output: 3745
Use the shared worker exchange for both publishers. AnalysisTaskMessagePublisher and JobPostingTaskMessagePublisher can publish to app.worker.analysis.exchange / app.worker.job-posting.exchange, while RabbitMqConfig binds both queues to workerExchange. If either publisher is overridden independently, messages go to an exchange the queues are not bound to and worker tasks are dropped. Inject workerExchange directly, or reuse its resolved name, instead of keeping separate per-publisher exchange properties.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/main/java/com/jobdri/jobdri_api/global/config/RabbitMqConfig.java` around
lines 18 - 23, The worker exchange is configured separately from the publishers,
which can cause `AnalysisTaskMessagePublisher` and
`JobPostingTaskMessagePublisher` to send messages to exchanges that
`RabbitMqConfig.workerExchange` does not bind to. Update the publisher wiring to
inject and reuse the shared `workerExchange` bean (or its resolved name) instead
of reading independent publisher exchange properties, so both publishers always
target the same exchange as the queue bindings.
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (1)
src/main/resources/application-prod.yaml (1)
93-98: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueOptional: analysis block omits queue/processing timeout overrides.
Unlike
job-posting, theanalysisblock exposes onlymax-retry-count. If the analysis timeout policy is meant to be operator-tunable like job-posting, consider addingqueue-timeout-minutes/processing-timeout-minutesenv-backed keys for parity; otherwise it silently relies on hardcoded@Valuedefaults.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/main/resources/application-prod.yaml` around lines 93 - 98, The analysis configuration block currently exposes only max-retry-count and leaves timeout behavior hidden behind default `@Value` values. Update the analysis section in application-prod.yaml to match the job-posting pattern by adding env-backed queue-timeout-minutes and processing-timeout-minutes keys alongside the existing analysis.exchange, analysis.queue, analysis.routing-key, analysis.dlq, and analysis.max-retry-count entries so operators can override them consistently.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In
`@src/main/java/com/jobdri/jobdri_api/domain/jobposting/entity/JobPostingAsyncTask.java`:
- Around line 110-117: `markRetryScheduled` in `JobPostingAsyncTask` should
refresh queue metadata when a task is re-queued: update `submittedAt` to the
current time so `expireTimedOutTaskIfNeeded()` uses the new enqueue time, and
clear attempt-scoped fields such as `workerId` and `startedAt` alongside the
existing status/message/failure updates. Keep the retry reset logic in
`markRetryScheduled` consistent with the task lifecycle so a retried pending
task is treated as a fresh queue entry.
In
`@src/main/java/com/jobdri/jobdri_api/global/mq/service/RabbitPublishSupport.java`:
- Around line 26-64: The `RabbitPublishSupport.publish()` flow is blocking the
HTTP/request thread by waiting in `awaitPublisherConfirm`, which can exhaust the
servlet pool under load. Move publisher-confirm waiting off the request path (or
make it fully async) and ensure late confirms are handled idempotently so a
timeout/failure does not delete state that worker callbacks still need. Focus
the fix around `publish`, `awaitPublisherConfirm`, and the
`CorrelationData`/confirm handling so retries and callbacks do not produce
`*_ASYNC_TASK_NOT_FOUND` errors.
In
`@src/test/java/com/jobdri/jobdri_api/global/mq/service/RabbitPublishSupportIntegrationTest.java`:
- Around line 24-58: The RabbitPublishSupportIntegrationTest is still hard-wired
to a local RabbitMQ broker via its Spring test properties, but CI does not start
one. Update this test setup by either wiring RabbitMQ through a CI service
container or converting the test to use Testcontainers/conditional execution,
and keep the configuration anchored around RabbitPublishSupportIntegrationTest,
RabbitTemplate, RabbitAdmin, and the DirectExchange bean so it only runs when a
broker is available.
---
Nitpick comments:
In `@src/main/resources/application-prod.yaml`:
- Around line 93-98: The analysis configuration block currently exposes only
max-retry-count and leaves timeout behavior hidden behind default `@Value` values.
Update the analysis section in application-prod.yaml to match the job-posting
pattern by adding env-backed queue-timeout-minutes and
processing-timeout-minutes keys alongside the existing analysis.exchange,
analysis.queue, analysis.routing-key, analysis.dlq, and analysis.max-retry-count
entries so operators can override them consistently.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 4d11173d-d3c1-440d-baff-3cbc8c704296
📒 Files selected for processing (36)
.gradle-local/wrapper/dists/gradle-8.14.4-bin/92wwslzcyst3phie3o264zltu/gradle-8.14.4-bin.zip.lck.gradle-local/wrapper/dists/gradle-8.14.4-bin/92wwslzcyst3phie3o264zltu/gradle-8.14.4-bin.zip.partops/db/migrations/20260704_job_posting_async_tasks_user_id.sqlops/db/migrations/20260704_job_posting_async_tasks_worker_metadata.sqlsrc/main/java/com/jobdri/jobdri_api/domain/analysis/dto/worker/AnalysisTaskMessage.javasrc/main/java/com/jobdri/jobdri_api/domain/analysis/service/AnalysisAsyncFacadeService.javasrc/main/java/com/jobdri/jobdri_api/domain/analysis/service/AnalysisAsyncProcessor.javasrc/main/java/com/jobdri/jobdri_api/domain/analysis/service/AnalysisTaskMessagePublisher.javasrc/main/java/com/jobdri/jobdri_api/domain/analysis/service/AnalysisWorkerBridgeService.javasrc/main/java/com/jobdri/jobdri_api/domain/jobposting/controller/JobPostingAiController.javasrc/main/java/com/jobdri/jobdri_api/domain/jobposting/controller/JobPostingWorkerInternalController.javasrc/main/java/com/jobdri/jobdri_api/domain/jobposting/dto/response/JobPostingAsyncStatusResponse.javasrc/main/java/com/jobdri/jobdri_api/domain/jobposting/dto/worker/JobPostingIngestTaskMessage.javasrc/main/java/com/jobdri/jobdri_api/domain/jobposting/dto/worker/JobPostingWorkerFailureRequest.javasrc/main/java/com/jobdri/jobdri_api/domain/jobposting/dto/worker/JobPostingWorkerRetryRequest.javasrc/main/java/com/jobdri/jobdri_api/domain/jobposting/dto/worker/JobPostingWorkerRunningRequest.javasrc/main/java/com/jobdri/jobdri_api/domain/jobposting/entity/JobPostingAsyncTask.javasrc/main/java/com/jobdri/jobdri_api/domain/jobposting/repository/JobPostingAsyncTaskRepository.javasrc/main/java/com/jobdri/jobdri_api/domain/jobposting/service/JobPostingAsyncFacadeService.javasrc/main/java/com/jobdri/jobdri_api/domain/jobposting/service/JobPostingAsyncProcessor.javasrc/main/java/com/jobdri/jobdri_api/domain/jobposting/service/JobPostingAsyncTaskService.javasrc/main/java/com/jobdri/jobdri_api/domain/jobposting/service/JobPostingTaskMessagePublisher.javasrc/main/java/com/jobdri/jobdri_api/domain/jobposting/service/JobPostingWorkerBridgeService.javasrc/main/java/com/jobdri/jobdri_api/domain/payment/entity/Payment.javasrc/main/java/com/jobdri/jobdri_api/domain/payment/service/PaymentService.javasrc/main/java/com/jobdri/jobdri_api/domain/payment/service/PaymentTransactionService.javasrc/main/java/com/jobdri/jobdri_api/domain/payment/service/TossPaymentClient.javasrc/main/java/com/jobdri/jobdri_api/global/mq/service/RabbitPublishSupport.javasrc/main/resources/application-dev.yamlsrc/main/resources/application-prod.yamlsrc/test/java/com/jobdri/jobdri_api/domain/analysis/service/AnalysisAsyncFacadeServiceTest.javasrc/test/java/com/jobdri/jobdri_api/domain/analysis/service/AnalysisWorkerBridgeServiceTest.javasrc/test/java/com/jobdri/jobdri_api/domain/jobposting/service/JobPostingAsyncFacadeServiceTest.javasrc/test/java/com/jobdri/jobdri_api/domain/jobposting/service/JobPostingAsyncTaskServiceTest.javasrc/test/java/com/jobdri/jobdri_api/domain/payment/service/PaymentServiceTest.javasrc/test/java/com/jobdri/jobdri_api/global/mq/service/RabbitPublishSupportIntegrationTest.java
💤 Files with no reviewable changes (2)
- src/main/java/com/jobdri/jobdri_api/domain/analysis/dto/worker/AnalysisTaskMessage.java
- src/main/java/com/jobdri/jobdri_api/domain/analysis/service/AnalysisAsyncFacadeService.java
✅ Files skipped from review due to trivial changes (1)
- src/test/java/com/jobdri/jobdri_api/domain/jobposting/service/JobPostingAsyncTaskServiceTest.java
🚧 Files skipped from review as they are similar to previous changes (4)
- src/main/java/com/jobdri/jobdri_api/domain/analysis/service/AnalysisTaskMessagePublisher.java
- src/main/resources/application-dev.yaml
- src/main/java/com/jobdri/jobdri_api/domain/analysis/service/AnalysisAsyncProcessor.java
- src/main/java/com/jobdri/jobdri_api/domain/analysis/service/AnalysisWorkerBridgeService.java
| public void markRetryScheduled(FailureReason failureReason, String errorMessage, int retryCount) { | ||
| this.status = TaskStatus.PENDING; | ||
| this.message = "채용 공고 비동기 재시도를 대기 중입니다."; | ||
| this.failureReason = failureReason; | ||
| this.error = errorMessage; | ||
| this.retryCount = Math.max(0, retryCount); | ||
| this.completedAt = null; | ||
| } |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Find where markRetryScheduled is invoked and whether submittedAt is re-stamped on retry publish
rg -nP '\bmarkRetryScheduled\b' --type=java -C3
rg -nP 'submittedAt' --type=java -g '!**/test/**' -C2Repository: JobDri-Developer/BackEnd
Length of output: 162
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Map the relevant classes before reading targeted sections
fd -a 'JobPostingAsyncTask.java|JobPostingAsyncTaskService.java|*AsyncTask*' src/main/java
# Locate retry/timeout-related methods and their call sites
rg -n --hidden --glob '!**/test/**' '\bmarkRetryScheduled\b|\bexpireTimedOutTaskIfNeeded\b|\bisExpired\(|\bsubmittedAt\b|\bworkerId\b|\bstartedAt\b' src/main/java
# Show the task entity around the retry method
sed -n '1,220p' src/main/java/com/jobdri/jobdri_api/domain/jobposting/entity/JobPostingAsyncTask.java
# Show the service sections that evaluate queue timeout / retry handling
sed -n '1,260p' src/main/java/com/jobdri/jobdri_api/domain/jobposting/service/JobPostingAsyncTaskService.javaRepository: JobDri-Developer/BackEnd
Length of output: 567
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Find exact relevant files in the repository
fd --type f --hidden 'JobPostingAsyncTask.java' src/main/java
fd --type f --hidden 'JobPostingAsyncTaskService.java' src/main/java
# Search for retry and timeout symbols across the main Java sources
rg -n --hidden --glob '!**/test/**' '\bmarkRetryScheduled\b|\bexpireTimedOutTaskIfNeeded\b|\bisExpired\(|\bsubmittedAt\b|\bworkerId\b|\bstartedAt\b' src/main/java
# Print the task entity around the retry method
sed -n '1,220p' src/main/java/com/jobdri/jobdri_api/domain/jobposting/entity/JobPostingAsyncTask.java
# Print the service around timeout handling and retry publishing
sed -n '1,320p' src/main/java/com/jobdri/jobdri_api/domain/jobposting/service/JobPostingAsyncTaskService.javaRepository: JobDri-Developer/BackEnd
Length of output: 22947
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Find the exact repository paths for the relevant classes
fd --fixed-strings 'JobPostingAsyncTask.java' src/main/java
fd --fixed-strings 'JobPostingAsyncTaskService.java' src/main/java
# Search retry/timeout-related symbols in the main Java sources
rg -n --hidden --glob '!**/test/**' '\bmarkRetryScheduled\b|\bexpireTimedOutTaskIfNeeded\b|\bisExpired\(|\bsubmittedAt\b|\bworkerId\b|\bstartedAt\b' src/main/java
# Read the entity and service implementations in focused slices
sed -n '1,220p' src/main/java/com/jobdri/jobdri_api/domain/jobposting/entity/JobPostingAsyncTask.java
sed -n '1,320p' src/main/java/com/jobdri/jobdri_api/domain/jobposting/service/JobPostingAsyncTaskService.javaRepository: JobDri-Developer/BackEnd
Length of output: 22947
Retry scheduling should refresh queue metadata
markRetryScheduled leaves submittedAt unchanged, but expireTimedOutTaskIfNeeded() expires PENDING tasks against that timestamp. A retried task can therefore be marked QUEUE_TIMEOUT before the next attempt starts. Refresh submittedAt here and clear attempt-scoped fields like workerId and startedAt when re-queuing.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In
`@src/main/java/com/jobdri/jobdri_api/domain/jobposting/entity/JobPostingAsyncTask.java`
around lines 110 - 117, `markRetryScheduled` in `JobPostingAsyncTask` should
refresh queue metadata when a task is re-queued: update `submittedAt` to the
current time so `expireTimedOutTaskIfNeeded()` uses the new enqueue time, and
clear attempt-scoped fields such as `workerId` and `startedAt` alongside the
existing status/message/failure updates. Keep the retry reset logic in
`markRetryScheduled` consistent with the task lifecycle so a retried pending
task is treated as a fresh queue entry.
| public void publish( | ||
| String exchange, | ||
| String routingKey, | ||
| Object payload, | ||
| String correlationId, | ||
| String failureMessage, | ||
| MessagePostProcessor messagePostProcessor | ||
| ) { | ||
| CorrelationData correlationData = new CorrelationData(correlationId); | ||
| rabbitTemplate.convertAndSend(exchange, routingKey, payload, messagePostProcessor, correlationData); | ||
| awaitPublisherConfirm(correlationData, failureMessage); | ||
| } | ||
|
|
||
| private void awaitPublisherConfirm(CorrelationData correlationData, String failureMessage) { | ||
| try { | ||
| CorrelationData.Confirm confirm = correlationData.getFuture() | ||
| .get(publishConfirmTimeoutMillis, TimeUnit.MILLISECONDS); | ||
|
|
||
| if (confirm == null || !confirm.isAck()) { | ||
| throw new GeneralException( | ||
| GeneralErrorCode.SERVICE_UNAVAILABLE, | ||
| failureMessage + buildReasonSuffix(confirm != null ? confirm.getReason() : null) | ||
| ); | ||
| } | ||
|
|
||
| ReturnedMessage returnedMessage = correlationData.getReturned(); | ||
| if (returnedMessage != null) { | ||
| throw new GeneralException( | ||
| GeneralErrorCode.SERVICE_UNAVAILABLE, | ||
| failureMessage + " routingKey=" + returnedMessage.getRoutingKey() | ||
| ); | ||
| } | ||
| } catch (InterruptedException e) { | ||
| Thread.currentThread().interrupt(); | ||
| throw new GeneralException(GeneralErrorCode.SERVICE_UNAVAILABLE, failureMessage); | ||
| } catch (ExecutionException | TimeoutException e) { | ||
| throw new GeneralException(GeneralErrorCode.SERVICE_UNAVAILABLE, failureMessage); | ||
| } | ||
| } |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟠 Major | 🏗️ Heavy lift
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '\n== Files ==\n'
git ls-files \
src/main/java/com/jobdri/jobdri_api/global/mq/service/RabbitPublishSupport.java \
src/main/java/com/jobdri/jobdri_api/global/mq/service \
src/main/java/com/jobdri/jobdri_api/**/JobPostingTaskMessagePublisher.java \
src/main/java/com/jobdri/jobdri_api/**/AnalysisTaskMessagePublisher.java \
src/main/java/com/jobdri/jobdri_api/**/JobPostingAsyncFacadeService.java \
src/main/java/com/jobdri/jobdri_api/**/AnalysisAsyncFacadeService.java \
src/main/java/com/jobdri/jobdri_api/** \
src/main/java/**/controller/** \
src/main/java/**/internal/** \
src/main/java/**/task/** \
2>/dev/null | sed 's#^`#-` #'
printf '\n== Outline RabbitPublishSupport ==\n'
ast-grep outline src/main/java/com/jobdri/jobdri_api/global/mq/service/RabbitPublishSupport.java --view expanded || true
printf '\n== Outline likely callers ==\n'
for f in \
$(git ls-files 'src/main/java/**/JobPostingTaskMessagePublisher.java' 'src/main/java/**/AnalysisTaskMessagePublisher.java' 'src/main/java/**/JobPostingAsyncFacadeService.java' 'src/main/java/**/AnalysisAsyncFacadeService.java' 2>/dev/null); do
echo "--- $f"
ast-grep outline "$f" --view expanded || true
done
printf '\n== Search for timeout / delete / task not found ==\n'
rg -n "publishConfirmTimeoutMillis|delete\\(|not found|TASK_NOT_FOUND|SERVICE_UNAVAILABLE|correlationData|getReturned\\(|awaitPublisherConfirm|convertAndSend\\(" src/main/java || trueRepository: JobDri-Developer/BackEnd
Length of output: 29932
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo '== RabbitPublishSupport =='
sed -n '1,220p' src/main/java/com/jobdri/jobdri_api/global/mq/service/RabbitPublishSupport.java
echo
echo '== JobPostingAsyncFacadeService =='
sed -n '1,240p' src/main/java/com/jobdri/jobdri_api/domain/jobposting/service/JobPostingAsyncFacadeService.java
echo
echo '== AnalysisAsyncFacadeService =='
sed -n '1,260p' src/main/java/com/jobdri/jobdri_api/domain/analysis/service/AnalysisAsyncFacadeService.java
echo
echo '== JobPostingWorkerBridgeService =='
sed -n '1,220p' src/main/java/com/jobdri/jobdri_api/domain/jobposting/service/JobPostingWorkerBridgeService.java
echo
echo '== AnalysisWorkerBridgeService =='
sed -n '1,240p' src/main/java/com/jobdri/jobdri_api/domain/analysis/service/AnalysisWorkerBridgeService.java
echo
echo '== Controllers mentioning async submit =='
rg -n "submit\\(" src/main/java/com/jobdri/jobdri_api/domain/jobposting/controller src/main/java/com/jobdri/jobdri_api/domain/analysis/controller || trueRepository: JobDri-Developer/BackEnd
Length of output: 24203
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo '== JobPostingAsyncProcessor =='
sed -n '1,240p' src/main/java/com/jobdri/jobdri_api/domain/jobposting/service/JobPostingAsyncProcessor.java
echo
echo '== AnalysisAsyncProcessor =='
sed -n '1,260p' src/main/java/com/jobdri/jobdri_api/domain/analysis/service/AnalysisAsyncProcessor.java
echo
echo '== JobPostingAiController submit endpoint =='
sed -n '1,180p' src/main/java/com/jobdri/jobdri_api/domain/jobposting/controller/JobPostingAiController.java
echo
echo '== AnalysisController submit endpoint =='
sed -n '1,140p' src/main/java/com/jobdri/jobdri_api/domain/analysis/controller/AnalysisController.java
echo
echo '== Worker internal controllers =='
sed -n '1,220p' src/main/java/com/jobdri/jobdri_api/domain/jobposting/controller/JobPostingWorkerInternalController.java
echo
sed -n '1,240p' src/main/java/com/jobdri/jobdri_api/domain/analysis/controller/AnalysisWorkerInternalController.javaRepository: JobDri-Developer/BackEnd
Length of output: 22418
Avoid waiting for publisher confirms on the HTTP thread
publish() blocks the request thread until a broker confirm arrives, so bursts of submissions can exhaust the servlet pool. The timeout path is also unsafe: a late confirm can still mean the message was accepted, but the current failure handling deletes the pending task, which leaves worker callbacks hitting *_ASYNC_TASK_NOT_FOUND and can trigger duplicate retries. Consider moving confirm handling off the request path or making late confirms/task state transitions idempotent.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In
`@src/main/java/com/jobdri/jobdri_api/global/mq/service/RabbitPublishSupport.java`
around lines 26 - 64, The `RabbitPublishSupport.publish()` flow is blocking the
HTTP/request thread by waiting in `awaitPublisherConfirm`, which can exhaust the
servlet pool under load. Move publisher-confirm waiting off the request path (or
make it fully async) and ensure late confirms are handled idempotently so a
timeout/failure does not delete state that worker callbacks still need. Focus
the fix around `publish`, `awaitPublisherConfirm`, and the
`CorrelationData`/confirm handling so retries and callbacks do not produce
`*_ASYNC_TASK_NOT_FOUND` errors.
| @SpringBootTest | ||
| @ActiveProfiles("test") | ||
| @TestPropertySource(properties = { | ||
| "spring.rabbitmq.host=localhost", | ||
| "spring.rabbitmq.port=5672", | ||
| "spring.rabbitmq.username=guest", | ||
| "spring.rabbitmq.password=guest", | ||
| "spring.rabbitmq.publisher-confirm-type=correlated", | ||
| "spring.rabbitmq.publisher-returns=true", | ||
| "spring.rabbitmq.template.mandatory=true" | ||
| }) | ||
| class RabbitPublishSupportIntegrationTest { | ||
|
|
||
| @Autowired | ||
| private RabbitPublishSupport rabbitPublishSupport; | ||
|
|
||
| @Autowired | ||
| private RabbitTemplate rabbitTemplate; | ||
|
|
||
| @Autowired | ||
| private RabbitAdmin rabbitAdmin; | ||
|
|
||
| @Autowired | ||
| private DirectExchange workerExchange; | ||
|
|
||
| @Value("${app.worker.job-posting.queue:jobdri.job-posting.ingest}") | ||
| private String queueName; | ||
|
|
||
| @Value("${app.worker.job-posting.routing-key:job-posting.ingest}") | ||
| private String routingKey; | ||
|
|
||
| @BeforeEach | ||
| void purgeQueue() { | ||
| rabbitAdmin.purgeQueue(queueName, true); | ||
| } |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Look for broker provisioning / testcontainers / CI service config
rg -nP 'RabbitMQContainer|Testcontainers|`@EnabledIf`|rabbitmq' -g '!**/node_modules/**' -C2
fd -i -e yml -e yaml . .github 2>/dev/null | xargs -r rg -nl 'rabbitmq' 2>/dev/nullRepository: JobDri-Developer/BackEnd
Length of output: 248
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo '## Relevant files'
git ls-files '.github/**' 'docker*' '*compose*' 'src/test/resources/**' 'src/main/resources/**' | sed -n '1,200p'
echo
echo '## RabbitMQ/Testcontainers/CI references'
rg -n --hidden --glob '!**/node_modules/**' --glob '!**/target/**' \
'RabbitMQContainer|Testcontainers|`@EnabledIf`|`@DisabledIf`|spring\.rabbitmq|rabbitmq|localhost:5672|5672|guest/guest' \
.github src/test/resources src/main/resources src/test/java . 2>/dev/null | sed -n '1,260p'Repository: JobDri-Developer/BackEnd
Length of output: 4147
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo '## .github/workflows/ci.yml'
cat -n .github/workflows/ci.yml | sed -n '1,220p'
echo
echo '## src/test/resources/application-test.yaml'
cat -n src/test/resources/application-test.yaml | sed -n '1,220p'
echo
echo '## RabbitMQ-related main config'
cat -n src/main/resources/application.yaml | sed -n '1,220p'Repository: JobDri-Developer/BackEnd
Length of output: 4746
Provision RabbitMQ for this integration test
src/test/java/com/jobdri/jobdri_api/global/mq/service/RabbitPublishSupportIntegrationTest.java still binds to localhost:5672, but .github/workflows/ci.yml only runs ./gradlew clean test and does not start RabbitMQ. Add a CI service container or switch this test to Testcontainers/conditional execution so builds don’t fail when no broker is available.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In
`@src/test/java/com/jobdri/jobdri_api/global/mq/service/RabbitPublishSupportIntegrationTest.java`
around lines 24 - 58, The RabbitPublishSupportIntegrationTest is still
hard-wired to a local RabbitMQ broker via its Spring test properties, but CI
does not start one. Update this test setup by either wiring RabbitMQ through a
CI service container or converting the test to use Testcontainers/conditional
execution, and keep the configuration anchored around
RabbitPublishSupportIntegrationTest, RabbitTemplate, RabbitAdmin, and the
DirectExchange bean so it only runs when a broker is available.
✨ 어떤 이유로 PR를 하셨나요?
📋 세부 내용 - 왜 해당 PR이 필요한지 작업 내용을 자세하게 설명해주세요
📸 작업 화면 스크린샷
🚨 관련 이슈 번호 [#110]
Summary by CodeRabbit
New Features
Bug Fixes
Documentation / Chores / Tests