Skip to content

fix(node): map ipfs/arweave DB outages to 503 via bare ? (#251) - #254

Open
Ayush7614 wants to merge 2 commits into
Gitlawb:mainfrom
Ayush7614:fix/251-db-outage-503-ipfs-arweave
Open

fix(node): map ipfs/arweave DB outages to 503 via bare ? (#251)#254
Ayush7614 wants to merge 2 commits into
Gitlawb:mainfrom
Ayush7614:fix/251-db-outage-503-ipfs-arweave

Conversation

@Ayush7614

@Ayush7614 Ayush7614 commented Jul 27, 2026

Copy link
Copy Markdown

Summary

  • Replace .map_err(AppError::Internal) with bare ? on /api/v1/ipfs/pins, GET /ipfs/{cid}, and /api/v1/arweave/anchors DB calls.
  • Connection-class sqlx failures (PoolClosed, etc.) now downcast through From<anyhow::Error> into AppError::Db and return 503 db_unavailable, matching /api/v1/repos and /api/v1/peers.
  • Non-sqlx errors still become Internal via that same conversion.

Test plan

  • cargo test -p gitlawb-node pool_closed_via_anyhow_from_is_503_db_unavailable — downcast path
  • list_pins_closed_pool_returns_503_db_unavailable — closed-pool route (CI / DATABASE_URL)
  • list_anchors_closed_pool_returns_503_db_unavailable — closed-pool route (CI / DATABASE_URL)

Fixes #251

Summary by CodeRabbit

  • Bug Fixes
    • Database connection failures now return 503 Service Unavailable with the expected database-unavailable error payload, rather than an internal server error.
    • Updated error handling for Arweave anchor listing and IPFS pin/lookup requests to consistently report database outage conditions.
  • Tests
    • Added regression tests to confirm 503 behavior and the correct error code/message when the database connection pool is closed.

Replace .map_err(AppError::Internal) with bare ? so connection-class
sqlx failures downcast to AppError::Db and return 503 db_unavailable
on /ipfs/pins, /ipfs/{cid}, and /arweave/anchors (Gitlawb#251).
@coderabbitai

coderabbitai Bot commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: eec53798-e456-432b-864d-67f737f292d6

📥 Commits

Reviewing files that changed from the base of the PR and between 6cf5378 and 7cba310.

📒 Files selected for processing (1)
  • crates/gitlawb-node/src/api/ipfs.rs
🚧 Files skipped from review as they are similar to previous changes (1)
  • crates/gitlawb-node/src/api/ipfs.rs

📝 Walkthrough

Walkthrough

Changes

Database error propagation

Layer / File(s) Summary
Handler error propagation
crates/gitlawb-node/src/api/arweave.rs, crates/gitlawb-node/src/api/ipfs.rs
Selected database calls now use direct error propagation, allowing connection failures to map to db_unavailable.
Closed-pool regression coverage
crates/gitlawb-node/src/api/arweave.rs, crates/gitlawb-node/src/api/ipfs.rs, crates/gitlawb-node/src/error.rs
Tests verify closed SQL pools produce HTTP 503 responses with the expected database-unavailable payload and conversion behavior.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Possibly related PRs

  • Gitlawb/node#170 — Establishes shared SQLx pool-error classification for 503 responses.
  • Gitlawb/node#247 — Updates AppError HTTP error-body mapping and related tests.

Suggested labels: kind:test

Suggested reviewers: jatmn

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly matches the main change: mapping IPFS/Arweave DB outages to 503 via bare ?.
Description check ✅ Passed The description includes a clear summary, issue link, and test plan, though some template sections are left unfilled.
Linked Issues check ✅ Passed The PR updates all three affected routes to use bare ? and adds closed-pool regression tests, matching #251.
Out of Scope Changes check ✅ Passed The changes stay focused on DB outage handling and related tests, with no obvious unrelated code churn.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
crates/gitlawb-node/src/api/ipfs.rs (1)

80-86: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add closed-pool coverage for get_by_cid.

The handler now changes two database calls to rely on the anyhowAppError conversion, but the new regression test covers only list_pins. Add a valid-CID closed-pool request for /ipfs/{cid} and assert the 503 db_unavailable payload so both propagation points remain protected.

🤖 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 `@crates/gitlawb-node/src/api/ipfs.rs` around lines 80 - 86, Add regression
coverage for the get_by_cid handler using a valid CID and a closed database
pool, issuing a request to /ipfs/{cid}. Assert that it returns HTTP 503 with the
db_unavailable payload, matching the existing list_pins closed-pool test pattern
and protecting both error-propagation paths.
🤖 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.

Nitpick comments:
In `@crates/gitlawb-node/src/api/ipfs.rs`:
- Around line 80-86: Add regression coverage for the get_by_cid handler using a
valid CID and a closed database pool, issuing a request to /ipfs/{cid}. Assert
that it returns HTTP 503 with the db_unavailable payload, matching the existing
list_pins closed-pool test pattern and protecting both error-propagation paths.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: c8723f36-fd67-4348-bb4a-df2beee5bf0b

📥 Commits

Reviewing files that changed from the base of the PR and between 111cff7 and 6cf5378.

📒 Files selected for processing (3)
  • crates/gitlawb-node/src/api/arweave.rs
  • crates/gitlawb-node/src/api/ipfs.rs
  • crates/gitlawb-node/src/error.rs

@Ayush7614

Copy link
Copy Markdown
Author

@beardthelion — this PR addresses #251 that you filed. Happy to rebase/coordinate with #134 if that lands first on the same call sites.

@beardthelion beardthelion added crate:node gitlawb-node — the serving node and REST API kind:bug Defect fix — wrong or unsafe behavior subsystem:storage Blob/object store, Arweave, IPFS, archives labels Jul 27, 2026
CodeRabbit nit: exercise the /ipfs/{cid} list_all_repos bare-? path
against a closed pool so both DB propagation sites stay guarded.
@Ayush7614

Copy link
Copy Markdown
Author

@coderabbitai — addressed your nit:

Added get_by_cid_closed_pool_returns_503_db_unavailable — valid sha2-256 CIDv1 + closed pool → exact 503 / db_unavailable payload, matching the list_pins pattern so both bare-? DB sites stay covered.

@coderabbitai

coderabbitai Bot commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Tip

For best results, initiate chat on the files or code changes.

@Ayush7614 Thanks — that covers the previously untested get_by_cid database-propagation path with the expected closed-pool behavior.

🐇 ✅


If you found this review helpful, would you consider giving us a shout-out on X?

Thank you for using CodeRabbit!

@beardthelion beardthelion left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Approving. The mechanism is right and the sweep went further than the issue asked: after this, no live .map_err(AppError::Internal) remains on a db call anywhere in the crate (the two left in register.rs wrap UCAN work, not queries). I checked the downcast actually survives at all four call sites, since that is the part that silently breaks: list_pinned_cids, list_arweave_anchors, list_all_repos and list_visibility_rules_for_repos each end on a bare ? over fetch_all with no .context() layer, so there is nothing for downcast::<sqlx::Error>() to strip.

I verified the tests are load-bearing rather than green by construction. Reverting each production line back to .map_err(AppError::Internal) turns the matching test red with left: 500 / right: 503, and all three pass unmutated on 7cba310. The get_by_cid test you added on the last push covers the list_all_repos conversion specifically: revert ipfs.rs:80 and it fails at ipfs.rs:294.

Two notes, neither an ask, and one small thing worth doing.

Findings

  • [P3] Worth adding to the PR body: 500 responses on these routes now carry db_error where they carried internal_error
    crates/gitlawb-node/src/error.rs:150
    For a server-reported query error the status stays 500 and the message text is byte-identical, but the code string changes, and the description currently reads as though only the 503 case moves. I drove a dropped-column error through /api/v1/arweave/anchors to confirm: {"error":"db_error","message":"error returned from database: column \"cid\" does not exist"}. Nothing in the repo branches on that string, and the new code is what the sibling routes already emit for the same condition, so this is an alignment rather than a regression. Description fix only, no code change and no need for another push.

  • [P3] Coverage boundary on get_by_cid, recorded so it is not mistaken for full coverage later. Not an ask.
    crates/gitlawb-node/src/api/ipfs.rs:86
    The new test pins the first converted call site but not the second. With ipfs.rs:80 restored and only ipfs.rs:86 reverted, the test still passes, because a closed pool fails list_all_repos first and the second call is never reached. No test can isolate it with this injection, and the conversion there is the same one-line pattern, so I would leave it as is.

  • [P2] db_unavailable cannot see server-reported unavailability. Separate defect, not an ask on this PR.
    crates/gitlawb-node/src/error.rs:65
    The classifier matches only PoolTimedOut | PoolClosed | Io | Tls, so no SQLSTATE-bearing error can reach the 503 arm at all, which the probe above confirms. Meanwhile main.rs:685 already downcasts sqlx::Error::Database(db) and switches on code prefixes, treating everything outside 28/3D as transient, so the startup path and the request path currently disagree about the same condition. Which variant a real restart or connection-slot exhaustion emits is a direction I have not run, which is the other reason it does not belong in your change.

Merge order

Taking your offer: this goes first and #134 rebases onto it. #134 adds five .map_err(AppError::Internal)? sites in these same two files, which would put the 500 behavior straight back. I will raise those in that PR's round, so nothing there is on you.

Not yours, but relevant to whoever merges: PR Checks had never run on either head (fork approval pending), so the green on this PR was two triage checks rather than the suite. I have approved the run and it is going now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

crate:node gitlawb-node — the serving node and REST API kind:bug Defect fix — wrong or unsafe behavior subsystem:storage Blob/object store, Arweave, IPFS, archives

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Database outage renders as 500 internal_error, not the retryable 503, on /ipfs/pins, /ipfs/{cid} and /arweave/anchors

2 participants