fix(node): map ipfs/arweave DB outages to 503 via bare ? (#251) - #254
Conversation
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
📝 WalkthroughWalkthroughThe handlers now propagate SQLx database errors through ChangesDatabase error propagation
Estimated code review effort: 3 (Moderate) | ~20 minutes Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 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.
🧹 Nitpick comments (1)
crates/gitlawb-node/src/api/ipfs.rs (1)
80-86: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winAdd closed-pool coverage for
get_by_cid.The handler now changes two database calls to rely on the
anyhow→AppErrorconversion, but the new regression test covers onlylist_pins. Add a valid-CID closed-pool request for/ipfs/{cid}and assert the 503db_unavailablepayload 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
📒 Files selected for processing (3)
crates/gitlawb-node/src/api/arweave.rscrates/gitlawb-node/src/api/ipfs.rscrates/gitlawb-node/src/error.rs
|
@beardthelion — this PR addresses #251 that you filed. Happy to rebase/coordinate with #134 if that lands first on the same call sites. |
CodeRabbit nit: exercise the /ipfs/{cid} list_all_repos bare-? path
against a closed pool so both DB propagation sites stay guarded.
|
@coderabbitai — addressed your nit: Added |
|
Tip For best results, initiate chat on the files or code changes.
🐇 ✅ If you found this review helpful, would you consider giving us a shout-out on X? Thank you for using CodeRabbit! |
There was a problem hiding this comment.
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_errorwhere they carriedinternal_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/anchorsto 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. Withipfs.rs:80restored and onlyipfs.rs:86reverted, the test still passes, because a closed pool failslist_all_reposfirst 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_unavailablecannot see server-reported unavailability. Separate defect, not an ask on this PR.
crates/gitlawb-node/src/error.rs:65
The classifier matches onlyPoolTimedOut | PoolClosed | Io | Tls, so no SQLSTATE-bearing error can reach the 503 arm at all, which the probe above confirms. Meanwhilemain.rs:685already downcastssqlx::Error::Database(db)and switches on code prefixes, treating everything outside28/3Das 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.
|
@kevincodex1 this one is ready to merge. Approved by me on 07-27 and by jatmn on 07-29, both against the current head 7cba310, so neither review is stale. CI is green across all 12 checks and it merges clean. |
|
thanks for your contribution @Ayush7614 please rebase to main and kindly fix conflicts |
7cba310 to
3143404
Compare
|
@kevincodex1 rebased onto current Main had grown budget-timeout wrappers around Ready for another look / merge when CI is green. |
Gitlawb#248 added two test-only INSERT INTO peers fixtures that the peers-table writer guard now sees. Record them in LEDGER so test (stable)/beta pass on the rebased Gitlawb#254 head. Co-authored-by: Cursor <cursoragent@cursor.com>
347e933 to
3dc6855
Compare
Gitlawb#248 added two test-only INSERT INTO peers fixtures that the peers-table writer guard now sees. Record them in LEDGER so test (stable)/beta pass on the rebased Gitlawb#254 head.
Same Gitlawb#248 test-only INSERT INTO peers fixtures as on Gitlawb#254; record them in LEDGER so test (stable)/beta pass on the rebased Gitlawb#247 head.
Gitlawb#248 added two test-only INSERT INTO peers fixtures that the peers-table writer guard now sees. Record them in LEDGER so test (stable)/beta pass on the rebased Gitlawb#254 head.
00f161d to
9c30cc5
Compare
Same Gitlawb#248 test-only INSERT INTO peers fixtures as on Gitlawb#254; record them in LEDGER so test (stable)/beta pass on the rebased Gitlawb#247 head.
|
cc: @kevincodex1 |
|
hello @Ayush7614 kindly do rebase again and fix conflicts |
Rebased onto current main. Keep budget-timeout wrappers on get_by_cid; convert sqlx failures with Into<AppError> (not AppError::Internal) so pool closed/timeouts become 503 db_unavailable. Same for list_pins and arweave anchors, with closed-pool regressions.
|
@kevincodex1 — rebased again onto current Conflict resolution: Head: single commit Ready for merge when CI is green. |
9c30cc5 to
c29a91a
Compare
beardthelion
left a comment
There was a problem hiding this comment.
Re-reviewed on c29a91af, since the earlier approvals all predate today's two rebases.
The mechanism is right and the fail-closed ordering on the access-control query is intact: the timeout arm still returns before the loop, so a rule-map failure can never fall through to an unfiltered scan. Checked the conversion end to end, db_unavailable covers PoolTimedOut, PoolClosed, Io and Tls, and query or schema errors still land on the opaque 500 db_error body rather than being reclassified as retryable. Three of the four changed arms are pinned by the new tests, each verified by reverting the production line and watching the test go red.
Findings
-
[P2] Pin the visibility-rules error arm
crates/gitlawb-node/src/api/ipfs.rs:234
The closed-pool tests cannot reach this arm, since the pool is shut beforelist_all_reposand the handler returns at the first query. Reverting this line toAppError::Internal(e)leaves all three new tests green, so the one arm on the access-control query is unpinned. A test that seeds a repo (needed, the db function short-circuits on an empty id list), dropsvisibility_rules, then drivesGET /ipfs/{cid}does pin it: assert 500 with bodydb_error, which goes red withinternal_errorif the arm regresses. Not a blocker for merge. -
[P3] Update the Internal-arm comment that still names this handler
crates/gitlawb-node/src/error.rs:190
The comment givesGET /ipfs/{cid}as the example of a handler reaching the Internal arm via.map_err(AppError::Internal). This PR removes both of those call sites, so the example now points at a handler that no longer does it.error.rsis already in the diff.
#254 landed after this branch was last pushed and it moves the same surface. It converts get_by_cid's sqlx failure arms from AppError::Internal to a bare Into<AppError> conversion, so a connection-class failure downcasts to AppError::Db and answers 503 db_unavailable instead of a 500 (#251). Both textual conflicts were spurious alignments rather than real overlaps. Git matched this branch's provenance path against main's legacy-scan preload because both regions end the same way, and oids_for_cid does not exist on main at all. Resolved to this branch's structure, which already contains main's preload in its own place with all three of its queries clamped. The semantic change is the part that mattered and it was applied by hand afterwards, not inherited from the resolution. All ten clamped DB awaits in get_by_cid now use the bare conversion. Taking this branch's side wholesale would have silently reverted #251 across every one of them, including the four this branch added, since the arm shape they were written to mirror predated #254. Suite green on the merged tree with fmt, clippy, and metadata --locked clean.
Summary
.map_err(AppError::Internal)with bare?on/api/v1/ipfs/pins,GET /ipfs/{cid}, and/api/v1/arweave/anchorsDB calls.PoolClosed, etc.) now downcast throughFrom<anyhow::Error>intoAppError::Dband return 503db_unavailable, matching/api/v1/reposand/api/v1/peers.Internalvia that same conversion.Test plan
cargo test -p gitlawb-node pool_closed_via_anyhow_from_is_503_db_unavailable— downcast pathlist_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