Skip to content

refactor: remove web-application config and SSE feature for CLI#226

Merged
reddevilmidzy merged 2 commits intomainfrom
for-cli
Sep 22, 2025
Merged

refactor: remove web-application config and SSE feature for CLI#226
reddevilmidzy merged 2 commits intomainfrom
for-cli

Conversation

@reddevilmidzy
Copy link
Owner

@reddevilmidzy reddevilmidzy commented Sep 22, 2025

♟️ What’s this PR about?

axum 프레임워크를 걷어냈습니다. 이전에는 SSE로 링크 상태를 전송했는데, 현재는 로그만 출력하는 형태로 변경하였습니다.

🔗 Related Issues / PRs

part of #193

Summary by CodeRabbit

  • Refactor
    • Replaced streaming link-check updates with a single final summary result.
    • Removed the web server and HTTP endpoints (including health and stream); link checks now run directly from the app.
    • Eliminated environment-based configuration (port and CORS); behavior now relies on defaults or other sources.
  • Chores
    • Removed unused dependencies.
  • Tests
    • Removed SSE API tests corresponding to the deleted server functionality.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Sep 22, 2025

Walkthrough

Removes Axum-based HTTP server, configuration system, and SSE streaming. Deletes related dependencies and YAML configs. Refactors link check flow to compute and return a single summary result. Simplifies main to a small Tokio runtime invoking stream_link_checks with a fixed URL. Removes tests covering SSE and server behavior.

Changes

Cohort / File(s) Summary of Changes
Dependencies
Cargo.toml
Removed dependencies: axum = "0.8", dotenvy = "0.15", config = "0.15".
YAML configuration
configuration/base.yaml, configuration/local.yaml, configuration/production.yaml
Deleted app port from base; removed CORS blocks from local and production.
Configuration module removal
src/configuration.rs, src/lib.rs
Deleted configuration types, environment handling, builders, constants, and tests; removed pub use configuration::* and module declaration from crate root.
Server/startup removal
src/startup.rs, src/lib.rs
Removed Axum router, CORS setup, endpoints, Application type; removed pub use startup::* and module declaration from crate root.
Link checking flow refactor
src/link_checker/sse.rs
Replaced SSE streaming API with a function returning Result<LinkCheckSummaryEvent, String>; added per-link logging and final summary return; updated tests accordingly.
Entry point simplification
src/main.rs
Replaced async Axum server startup with a synchronous main creating a Tokio runtime to call stream_link_checks; removed configuration loading and server wiring.
API tests cleanup
tests/api/main.rs, tests/api/sse.rs
Removed SSE test module import and entire SSE API test file.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor User as Process Runner
  participant Main as main()
  participant RT as Tokio Runtime
  participant LC as stream_link_checks()
  participant Repo as Repo Scanner
  participant Checker as Link Checker

  User->>Main: start binary
  Main->>RT: build and block_on
  RT->>LC: stream_link_checks(repo_url, branch)
  LC->>Repo: collect links
  loop for each link
    LC->>Checker: check(link)
    Checker-->>LC: result
    LC->>LC: update counters, log
  end
  alt success
    LC-->>RT: LinkCheckSummaryEvent
    RT-->>Main: summary
    Main-->>User: exit 0
  else error
    LC-->>RT: Err(String)
    RT-->>Main: error
    Main-->>User: exit with error
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Title Check ✅ Passed The title "refactor: remove web-application config and SSE feature for CLI" succinctly and accurately summarizes the primary changes in this PR: removal of the web application/config layers and SSE-based streaming in favor of a CLI-oriented logging approach. The raw_summary shows removal of axum, configuration files/modules (configuration.rs, startup.rs, production/local/base YAML), SSE changes in src/link_checker/sse.rs, and main.rs updated to run the CLI flow, all of which map to the title. The phrasing is concise, specific, and meaningful to teammates scanning history.
Description Check ✅ Passed The PR description follows the repository template by including "What’s this PR about?" and "Related Issues / PRs" sections, clearly stating that axum and the SSE mechanism were removed and that link reporting now uses logs, and it references issue #193. These points are supported by the file-level summaries which show deleted configuration/startup modules, SSE refactor, and CLI main changes. The description is concise and sufficient for reviewers, though it could be improved by briefly listing breaking changes, impacted tests, or migration/testing steps.
✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch for-cli

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions github-actions bot added this to the 6차 MVP 구현 milestone Sep 22, 2025
@coveralls-official
Copy link

coveralls-official bot commented Sep 22, 2025

Pull Request Test Coverage Report for Build 17921117767

Details

  • 25 of 48 (52.08%) changed or added relevant lines in 2 files are covered.
  • 2 unchanged lines in 1 file lost coverage.
  • Overall coverage increased (+2.6%) to 79.699%

Changes Missing Coverage Covered Lines Changed/Added Lines %
src/link_checker/sse.rs 25 36 69.44%
src/main.rs 0 12 0.0%
Files with Coverage Reduction New Missed Lines %
src/main.rs 2 0.0%
Totals Coverage Status
Change from base Build 17917914292: 2.6%
Covered Lines: 899
Relevant Lines: 1128

💛 - Coveralls

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🧹 Nitpick comments (5)
src/link_checker/sse.rs (2)

103-151: Simplify the stream pipeline with for_each_concurrent.

Current map + buffer_unordered + for_each chain creates extra futures only to discard them. Use for_each_concurrent for clarity and less overhead.

-    stream::iter(links)
-        .map({
-            let counters = Arc::clone(&counters);
-            move |link| {
-                let counters = Arc::clone(&counters);
-                async move {
-                    let result = check_link(&link.url).await;
-                    counters.increment_total();
-                    match &result {
-                        LinkCheckResult::Valid => counters.increment_valid(),
-                        LinkCheckResult::Invalid(_) => counters.increment_invalid(),
-                        LinkCheckResult::Redirect(_) => counters.increment_redirect(),
-                        LinkCheckResult::GitHubFileMoved(_) => counters.increment_moved(),
-                    };
-                    let status = match &result {
-                        LinkCheckResult::Valid => "valid",
-                        LinkCheckResult::Invalid(_) => "invalid",
-                        LinkCheckResult::Redirect(_) => "redirect",
-                        LinkCheckResult::GitHubFileMoved(_) => "file_moved",
-                    };
-                    let message: Option<String> = match result {
-                        LinkCheckResult::Valid => None,
-                        LinkCheckResult::Invalid(msg) => Some(msg),
-                        LinkCheckResult::Redirect(url) => Some(format!("Redirected to: {url}")),
-                        LinkCheckResult::GitHubFileMoved(msg) => Some(format!("Moved to: {msg}")),
-                    };
-                    let message_str = message.as_deref().unwrap_or("");
-                    info!(
-                        url = %link.url,
-                        file_path = %link.file_path,
-                        line_number = link.line_number as u32,
-                        status = %status,
-                        message = %message_str,
-                        "link check"
-                    );
-                }
-            }
-        })
-        .buffer_unordered(10)
-        .for_each(|_| async {})
-        .await;
+    stream::iter(links)
+        .for_each_concurrent(10, {
+            let counters = Arc::clone(&counters);
+            move |link| {
+                let counters = Arc::clone(&counters);
+                async move {
+                    let result = check_link(&link.url).await;
+                    counters.increment_total();
+                    match &result {
+                        LinkCheckResult::Valid => counters.increment_valid(),
+                        LinkCheckResult::Invalid(_) => counters.increment_invalid(),
+                        LinkCheckResult::Redirect(_) => counters.increment_redirect(),
+                        LinkCheckResult::GitHubFileMoved(_) => counters.increment_moved(),
+                    };
+                    let status = match &result {
+                        LinkCheckResult::Valid => "valid",
+                        LinkCheckResult::Invalid(_) => "invalid",
+                        LinkCheckResult::Redirect(_) => "redirect",
+                        LinkCheckResult::GitHubFileMoved(_) => "file_moved",
+                    };
+                    let message: Option<String> = match result {
+                        LinkCheckResult::Valid => None,
+                        LinkCheckResult::Invalid(msg) => Some(msg),
+                        LinkCheckResult::Redirect(url) => Some(format!("Redirected to: {url}")),
+                        LinkCheckResult::GitHubFileMoved(msg) => Some(format!("Moved to: {msg}")),
+                    };
+                    let message_str = message.as_deref().unwrap_or("");
+                    info!(
+                        url = %link.url,
+                        file_path = %link.file_path,
+                        line_number = link.line_number as u32,
+                        status = %status,
+                        message = %message_str,
+                        "link check"
+                    );
+                }
+            }
+        })
+        .await;

151-160: Consider signaling failure in logs when invalid > 0.

Add a warning/error when invalid links exist to make scanning logs easier.

Example:

     let summary = counters.to_summary();
-    info!(
+    let level = if summary.invalid > 0 { tracing::Level::WARN } else { tracing::Level::INFO };
+    tracing::event!(
+        level,
         total = summary.total,
         valid = summary.valid,
         invalid = summary.invalid,
         redirect = summary.redirect,
         moved = summary.moved,
         "link check summary"
     );
src/main.rs (3)

21-32: Use the summary to set the process exit code (CLI UX).

Currently the result is discarded. Exit non‑zero when invalid links are found.

-    rt.block_on(async {
-        stream_link_checks(
-            "https://github.com/reddevilmidzy/queensac".to_string(),
-            None,
-        )
-        .await;
-    });
+    let exit_code = rt.block_on(async {
+        let summary = stream_link_checks(
+            "https://github.com/reddevilmidzy/queensac".to_string(),
+            None,
+        )
+        .await
+        #![allow(unused_must_use)];
+        // If you adopt Result from sse.rs change above, handle it here:
+        // .map_err(|e| { error!(error=%e, "link check failed"); 1 })?
+        ;
+        if summary.invalid > 0 { 2 } else { 0 }
+    });
+    std::process::exit(exit_code);

4-17: Minor: align copy to CLI (not “service”).

Change startup log to reflect a CLI run.

-    info!("Starting queensac service...");
+    info!("Starting queensac link-check CLI...");

4-17: Optional: simplify with #[tokio::main].

You can drop manual runtime construction.

-fn main() {
+#[tokio::main(flavor = "current_thread")]
+async fn main() {
   // Initialize tracing subscriber
   tracing_subscriber::fmt()
       .with_max_level(Level::INFO)
       .with_target(false)
       .with_thread_ids(true)
       .with_file(true)
       .with_line_number(true)
       .with_thread_names(true)
       .with_level(true)
       .with_ansi(true)
       .with_timer(KoreanTime)
       .pretty()
       .init();
-  let rt = tokio::runtime::Builder::new_current_thread()
-      .enable_all()
-      .build()
-      .expect("Failed to create Tokio runtime");
-  rt.block_on(async {
-      stream_link_checks("https://github.com/reddevilmidzy/queensac".to_string(), None).await;
-  });
+  let summary = stream_link_checks("https://github.com/reddevilmidzy/queensac".to_string(), None).await;
+  std::process::exit(if summary.invalid > 0 { 2 } else { 0 });
}

Also applies to: 21-32

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 71a0235 and cce1928.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (11)
  • Cargo.toml (0 hunks)
  • configuration/base.yaml (0 hunks)
  • configuration/local.yaml (0 hunks)
  • configuration/production.yaml (0 hunks)
  • src/configuration.rs (0 hunks)
  • src/lib.rs (0 hunks)
  • src/link_checker/sse.rs (2 hunks)
  • src/main.rs (2 hunks)
  • src/startup.rs (0 hunks)
  • tests/api/main.rs (0 hunks)
  • tests/api/sse.rs (0 hunks)
💤 Files with no reviewable changes (9)
  • src/configuration.rs
  • src/lib.rs
  • configuration/local.yaml
  • tests/api/sse.rs
  • configuration/production.yaml
  • tests/api/main.rs
  • src/startup.rs
  • configuration/base.yaml
  • Cargo.toml
🧰 Additional context used
🧬 Code graph analysis (2)
src/link_checker/sse.rs (2)
src/git/link_extractor.rs (1)
  • extract_links_from_repo_url (35-66)
src/link_checker/link.rs (1)
  • check_link (35-75)
src/main.rs (1)
src/link_checker/sse.rs (1)
  • stream_link_checks (79-161)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build

Comment on lines 168 to 175
async fn test_stream_link_checks_runs() {
let repo_url = "https://github.com/reddevilmidzy/kingsac".to_string();
let branch = Some("main".to_string());
let sse = stream_link_checks(repo_url, branch).await;
let mut stream = sse.into_response().into_body().into_data_stream();

// 스트림에서 이벤트를 수집
let mut events = Vec::new();
let mut buffer = String::new();

while let Some(chunk) = stream.next().await {
if let Ok(chunk) = chunk {
if let Ok(text) = String::from_utf8(chunk.to_vec()) {
buffer.push_str(&text);

if let Some(event_end) = buffer.find("\n\n") {
let event_str = buffer[..event_end].to_string();
buffer = buffer[event_end + 2..].to_string();
// "data: " 접두사를 제거하고 JSON 파싱
if let Some(json_str) = event_str.strip_prefix("data: ") {
if let Ok(json) = serde_json::from_str::<Value>(json_str) {
events.push(json);
}
}
}
}
}
}

assert!(!events.is_empty(), "No events were received");

assert!(events.last().is_some(), "Last event should exist");
if let Some(last_event) = events.last() {
assert!(last_event.get("total").is_some());
assert!(last_event.get("total").unwrap().as_u64().unwrap() > 0);
assert!(last_event.get("valid").is_some());
assert!(last_event.get("invalid").is_some());
assert!(last_event.get("redirect").is_some());
assert!(last_event.get("moved").is_some());
}

assert!(events.first().is_some(), "First event should exist");
if let Some(first_event) = events.first() {
assert!(first_event.get("url").is_some());
assert!(first_event.get("file_path").is_some());
assert!(first_event.get("line_number").is_some());
assert!(first_event.get("status").is_some());
}
let summary = stream_link_checks(repo_url, branch).await;
assert_eq!(
summary.total,
summary.valid + summary.invalid + summary.redirect + summary.moved
);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Test is flaky: hits live GitHub and network. Gate or mock.

This will be slow and flaky in CI. Either mark ignored by default or inject a check function to avoid network.

Minimal mitigation:

-    #[tokio::test]
+    #[tokio::test]
+    #[ignore = "uses live network and GitHub; move to integration or mock check_link"]

If you want, I can refactor stream_link_checks to accept a check_fn: Fn(&str) -> Future<Output=LinkCheckResult> for deterministic unit tests.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
async fn test_stream_link_checks_runs() {
let repo_url = "https://github.com/reddevilmidzy/kingsac".to_string();
let branch = Some("main".to_string());
let sse = stream_link_checks(repo_url, branch).await;
let mut stream = sse.into_response().into_body().into_data_stream();
// 스트림에서 이벤트를 수집
let mut events = Vec::new();
let mut buffer = String::new();
while let Some(chunk) = stream.next().await {
if let Ok(chunk) = chunk {
if let Ok(text) = String::from_utf8(chunk.to_vec()) {
buffer.push_str(&text);
if let Some(event_end) = buffer.find("\n\n") {
let event_str = buffer[..event_end].to_string();
buffer = buffer[event_end + 2..].to_string();
// "data: " 접두사를 제거하고 JSON 파싱
if let Some(json_str) = event_str.strip_prefix("data: ") {
if let Ok(json) = serde_json::from_str::<Value>(json_str) {
events.push(json);
}
}
}
}
}
}
assert!(!events.is_empty(), "No events were received");
assert!(events.last().is_some(), "Last event should exist");
if let Some(last_event) = events.last() {
assert!(last_event.get("total").is_some());
assert!(last_event.get("total").unwrap().as_u64().unwrap() > 0);
assert!(last_event.get("valid").is_some());
assert!(last_event.get("invalid").is_some());
assert!(last_event.get("redirect").is_some());
assert!(last_event.get("moved").is_some());
}
assert!(events.first().is_some(), "First event should exist");
if let Some(first_event) = events.first() {
assert!(first_event.get("url").is_some());
assert!(first_event.get("file_path").is_some());
assert!(first_event.get("line_number").is_some());
assert!(first_event.get("status").is_some());
}
let summary = stream_link_checks(repo_url, branch).await;
assert_eq!(
summary.total,
summary.valid + summary.invalid + summary.redirect + summary.moved
);
#[tokio::test]
#[ignore = "uses live network and GitHub; move to integration or mock check_link"]
async fn test_stream_link_checks_runs() {
let repo_url = "https://github.com/reddevilmidzy/kingsac".to_string();
let branch = Some("main".to_string());
let summary = stream_link_checks(repo_url, branch).await;
assert_eq!(
summary.total,
summary.valid + summary.invalid + summary.redirect + summary.moved
);
}
🤖 Prompt for AI Agents
In src/link_checker/sse.rs around lines 168 to 175, the test
test_stream_link_checks_runs is flaky because it performs live network requests
to GitHub; either mark the test as ignored by default (add #[ignore] above the
fn) or refactor stream_link_checks to accept an injected check function (e.g., a
parameter check_fn: impl Fn(&str) -> impl Future<Output = LinkCheckResult> +
Send + Sync) and update the test to pass a mock async check function that
returns deterministic LinkCheckResult values so the unit test no longer depends
on network.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (5)
src/main.rs (1)

19-19: 로그 문구: service → CLI

서버가 아닌 CLI 실행이므로 문구를 조정하면 혼동이 줄어듭니다.

-    info!("Starting queensac service...");
+    info!("Starting queensac CLI run...");
src/link_checker/sse.rs (4)

78-82: 에러를 String 대신 구체 타입으로 반환 고려

현재 Result<_, String>은 에러 컨텍스트를 잃습니다. git2::Error 그대로 또는 anyhow::Result를 권장합니다. 테스트/호출부 영향이 있으니 후속 PR로도 충분합니다.

-) -> Result<LinkCheckSummaryEvent, String> {
+) -> Result<LinkCheckSummaryEvent, git2::Error> {

그리고 에러 반환부에서 Err(e)로 그대로 전달.


88-98: 구조화 로그로 에러 필드화

에러 문자열 합치기 대신 필드로 남기면 검색/분석이 용이합니다.

-        Err(e) => {
-            error!("Error processing repository: {}", e);
-            return Err(e.to_string());
-        }
+        Err(e) => {
+            error!(error = %e, "Error processing repository");
+            return Err(e.to_string());
+        }

102-107: 불필요한 Arc::clone 중복

.map 바깥 캡쳐 1회 + 내부 1회면 충분합니다. 가독성 위해 중복 제거 권장.

-        .map({
-            let counters = Arc::clone(&counters);
-            move |link| {
-                let counters = Arc::clone(&counters);
+        .map({
+            let counters = counters.clone();
+            move |link| {
+                let counters = counters.clone();

144-146: 동시성 정도 상수/설정화

매직넘버 10 대신 상수 또는 env/CLI로 주입하면 운영 시 튜닝이 쉽습니다. (본 PR 범위 밖이면 패스)

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between cce1928 and 385a7c1.

📒 Files selected for processing (2)
  • src/link_checker/sse.rs (2 hunks)
  • src/main.rs (2 hunks)
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: reddevilmidzy
PR: reddevilmidzy/queensac#226
File: src/main.rs:21-32
Timestamp: 2025-09-22T15:50:19.498Z
Learning: User reddevilmidzy prefers to communicate in Korean and likes to keep PR scope focused and well-defined.
📚 Learning: 2025-09-22T15:50:19.498Z
Learnt from: reddevilmidzy
PR: reddevilmidzy/queensac#226
File: src/main.rs:21-32
Timestamp: 2025-09-22T15:50:19.498Z
Learning: User reddevilmidzy prefers to communicate in Korean and likes to keep PR scope focused and well-defined.

Applied to files:

  • src/main.rs
🧬 Code graph analysis (2)
src/main.rs (1)
src/link_checker/sse.rs (1)
  • stream_link_checks (79-158)
src/link_checker/sse.rs (2)
src/git/link_extractor.rs (1)
  • extract_links_from_repo_url (35-66)
src/link_checker/link.rs (1)
  • check_link (35-75)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build
🔇 Additional comments (6)
src/main.rs (2)

1-1: KoreanTime 경로 재검증 또는 re-export 필요

크레이트 루트에서 KoreanTime이 re-export되지 않았다면 이 import는 실패합니다. 모듈 경로로 바꾸거나(queensac::domain::time::KoreanTime) 루트에서 pub use 하세요.

다음 스크립트로 공개 re-export 여부를 확인해 주세요.

#!/bin/bash
# KoreanTime / stream_link_checks re-export 확인
rg -nC2 -g 'src/**' $'^\\s*pub\\s+use\\b.*KoreanTime\\b|^\\s*pub\\s+(struct|type)\\s+KoreanTime\\b'
rg -nC2 -g 'src/**' $'^\\s*pub\\s+use\\b.*stream_link_checks\\b|^\\s*pub\\s+(async\\s+)?fn\\s+stream_link_checks\\b'

선호하시면 main.rs에서 바로 수정:

-use queensac::{KoreanTime, stream_link_checks};
+use queensac::stream_link_checks;
+use queensac::domain::time::KoreanTime;

21-25: Tokio current_thread 선택 적절함

CLI 단일 러너에 new_current_thread().enable_all() 구성이 적합합니다. 👍

src/link_checker/sse.rs (4)

67-75: 원자 카운터 요약 로드 OK

Relaxed 로드/스토어는 카운팅 용도에 적절하며 .await 이후 최종 합산 시점에 충분합니다.


148-157: 요약 로그 + 반환 형태 적절

최종 합산 후 요약 로그를 남기고 Ok(summary) 반환하는 흐름이 명확합니다.


165-175: 실네트워크 의존 테스트는 flaky — 기본 무시 처리

라이브 GitHub/네트워크 의존으로 CI 불안정합니다. 우선 #[ignore]를 권장합니다. (모의 주입 리팩터는 후속 이슈로)

-    #[tokio::test]
+    #[tokio::test]
+    #[ignore = "uses live network and GitHub; move to integration or mock check_link"]
     async fn test_stream_link_checks_runs() {

9-16: SSE 제거 후 남은 타입 정리 (LinkCheckEvent)

rg 결과: 정의(src/link_checker/sse.rs)와 re-export(src/link_checker/mod.rs)에서만 발견되며 저장소 내부에 다른 사용처는 없습니다.
조치: src/link_checker/sse.rs에서 LinkCheckEvent 구조체 삭제 및 src/link_checker/mod.rs의 pub use에서 LinkCheckEvent 제거.
주의: 공개 API 변경이므로 외부 소비자(크레이트 사용자) 존재 여부와 CI/통합테스트를 확인하고, 필요 시 deprecated 단계·마이그레이션 안내를 추가.

Comment on lines +26 to +35
rt.block_on(async {
if let Err(e) = stream_link_checks(
"https://github.com/reddevilmidzy/queensac".to_string(),
None,
)
.await
{
error!("Failed to stream link checks: {}", e);
}
};

// Build application
let app = match Application::build(configuration).await {
Ok(app) => app,
Err(e) => {
error!("Failed to build application: {}", e);
std::process::exit(1);
}
};

// Create socket address
let addr = SocketAddr::from(([127, 0, 0, 1], app.port));
info!("Server listening on {}", addr);

// Start the server
let listener = match net::TcpListener::bind(addr).await {
Ok(listener) => listener,
Err(e) => {
error!("Failed to bind to address {}: {}", addr, e);
std::process::exit(1);
}
};

info!("queensac service is running on http://{}", addr);

// Serve the application
if let Err(e) = axum::serve(listener, app.router).await {
error!("Server error: {}", e);
std::process::exit(1);
}
});
Copy link
Contributor

@coderabbitai coderabbitai bot Sep 22, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

실패 시 비영(非零) 종료코드로 종료하세요

현재는 에러를 로그만 남기고 종료코드 0으로 끝납니다. CI/스크립트 연계 시 실패를 감지하지 못합니다.

아래처럼 반환 코드를 받아 std::process::exit 하세요.

-    rt.block_on(async {
-        if let Err(e) = stream_link_checks(
-            "https://github.com/reddevilmidzy/queensac".to_string(),
-            None,
-        )
-        .await
-        {
-            error!("Failed to stream link checks: {}", e);
-        }
-    });
+    let exit_code = rt.block_on(async {
+        match stream_link_checks(
+            "https://github.com/reddevilmidzy/queensac".to_string(),
+            None,
+        )
+        .await {
+            Ok(_) => 0,
+            Err(e) => {
+                error!("Failed to stream link checks: {}", e);
+                1
+            }
+        }
+    });
+    std::process::exit(exit_code);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
rt.block_on(async {
if let Err(e) = stream_link_checks(
"https://github.com/reddevilmidzy/queensac".to_string(),
None,
)
.await
{
error!("Failed to stream link checks: {}", e);
}
};
// Build application
let app = match Application::build(configuration).await {
Ok(app) => app,
Err(e) => {
error!("Failed to build application: {}", e);
std::process::exit(1);
}
};
// Create socket address
let addr = SocketAddr::from(([127, 0, 0, 1], app.port));
info!("Server listening on {}", addr);
// Start the server
let listener = match net::TcpListener::bind(addr).await {
Ok(listener) => listener,
Err(e) => {
error!("Failed to bind to address {}: {}", addr, e);
std::process::exit(1);
}
};
info!("queensac service is running on http://{}", addr);
// Serve the application
if let Err(e) = axum::serve(listener, app.router).await {
error!("Server error: {}", e);
std::process::exit(1);
}
});
let exit_code = rt.block_on(async {
match stream_link_checks(
"https://github.com/reddevilmidzy/queensac".to_string(),
None,
)
.await {
Ok(_) => 0,
Err(e) => {
error!("Failed to stream link checks: {}", e);
1
}
}
});
std::process::exit(exit_code);
🤖 Prompt for AI Agents
In src/main.rs around lines 26 to 35, the async block logs errors but still
returns exit code 0; change the control flow to capture the Result from
rt.block_on and, on Err(e), log the error and call std::process::exit with a
non-zero code (e.g., 1). Concretely, have rt.block_on return the Result from
stream_link_checks (or assign the block result to a variable), then if it is
Err(e) call error! with the error and immediately call std::process::exit(1) so
the process exits non-zero for CI/scripts to detect failure.

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이후 --args 받는 기능 구현할 때 반영할게욥

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@reddevilmidzy 네, 좋습니다! CLI 인자 파싱 기능과 함께 구현하시는 게 합리적인 접근이네요. PR 범위를 명확하게 유지하는 것이 좋은 접근 방식입니다. 👍

현재 PR은 웹 서버에서 CLI로의 전환에 집중하고, 향후 CLI 기능 개선 시 적절한 종료 코드 처리를 함께 구현하시면 될 것 같습니다.


🧠 Learnings used
Learnt from: reddevilmidzy
PR: reddevilmidzy/queensac#226
File: src/main.rs:21-32
Timestamp: 2025-09-22T15:50:19.498Z
Learning: User reddevilmidzy prefers to communicate in Korean and likes to keep PR scope focused and well-defined.

@reddevilmidzy reddevilmidzy merged commit 68c4caf into main Sep 22, 2025
6 checks passed
@reddevilmidzy reddevilmidzy deleted the for-cli branch September 22, 2025 16:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant