Repository navigation
fix(hardcover): stop the language evidence query timing out (#3333) - #3334
Merged
vavallee merged 1 commit intoOct 18, 2026
Merged
Conversation
…#3333) The editions lookup behind GetAuthorWorkLanguageEvidence, and its follow-up for blank-language works, joined the book.slug and book_id predicates in one _or. Hardcover cannot serve that from an index: the query ran until Hardcover cancelled it with HTTP 408 after about 15 s, so every author with Hardcover works lost 45-70 s to retries and its works fell back to the default-edition language. Either predicate on its own answers in under a second with the same rows. Send the slug predicate alone, declaring only the variables it uses, and run the book_id predicate as a second query only when some works are named by numeric id, merging the rows by book id. A failure of either query still fails the lookup, so a partial answer never counts as proof that a work has no allowed edition. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Uģis <berzinsu@gmail.com>
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
vavallee
approved these changes
Oct 18, 2026
vavallee
left a comment
Owner
There was a problem hiding this comment.
Checked on 1f34c29: both language evidence queries now avoid the slug/book_id OR, the merged results match the old ones, a failing query returns no partial evidence, and the tests reject the OR by behaviour. Thank you for the measurements in the issue, they made this quick to verify.
3 of 4 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
GetAuthorWorkLanguageEvidenceand its follow-up for blank-language works (resolveBlankWorkLanguages) both filtered editions with{_or: [{book: {slug: {_in: $slugs}}}, {book_id: {_in: $bookIds}}]}. Hardcover can't serve that_orfrom an index, so the query ran until Hardcover cancelled it with HTTP 408 at about 15 s. Bindery's own 15 s client timeout fired first andquery()retried twice, so every author with Hardcover works lost 45–70 s and its works fell back to the default-edition language.Both lookups now go through one helper,
fetchWorkEditions. It sends the slug predicate on its own and adds a separatebook_idquery only when some works are named by numeric id.bookIDsis filled only for numeric slugs, so in practice each lookup is one query. Rows from the two queries are merged by book id. Each query declares only the variables it uses, because Hasura rejects both declared-but-unused and undeclared variables withvalidation-failed.Closes #3333.
Implementation notes
_or. The issue names only the allowed-language query, butGetAuthorWorkKnownLanguages(added in fix(metadata): ISBN cache scope, supplement translations, OpenLibrary cover_edition, rebind editions #3102; the allowed-language query itself dates from fix(hardcover): don't treat translated default editions as work language #2754) uses the same predicate and also gets a 408. I measured it live at 15.4 s for Oliver Burkeman. Onmainit never runs, because the first query always fails before it. Fixing only the first query would have moved the timeout into the follow-up, where the failure is logged only at DEBUG.limitis the number of works it names. For the slug query that is the oldlen(evidence), and for thebook_idquery it is the number of ids.distinct_on: [book_id]andorder_by, so a work matched by both comes back as the same row, and the duplicate is dropped. Callers still key rows byhcBookRef.foreignID(), as before.TestGetAuthorWorkLanguageEvidence_BatchesAllowedEditionLookupexpected exactly one request carryingbookIds: [42], which encoded the_or. It now expects one slug query and onebook_idquery and checks the variables and limit of each.How it was verified
The new tests fail on main for the reason in the issue
language_evidence_predicates_test.goadds a fake Hardcover that behaves like the real one where it matters here:book.slugandbook_idpredicates{"error":"Request timeout"}, the body Hardcover returns live, where it takes about 15 svalidation-failederrorbook_idpredicate and the language filter, withdistinct_on(book_id)and$limitappliedThe new test file run against unmodified
main(b0b99f7e):EitherPredicateFailingReturnsNoEvidenceguards the semantics rather than reproducing the bug, so it passes onmaintoo (any failure there already returned no evidence).With this PR:
I also checked two mutations locally (not committed):
_orSlugNamedWorksQueryBySlugAlone,NumericIDsQueriedSeparatelyAndMergedEitherPredicateFailingReturnsNoEvidence(both subtests),FailureReturnsNoEvidenceLive against Hardcover
I captured the exact query text this branch's client sends and posted it with a real token, using
languageCodes: ["en", "eng"](whatLanguageCodeVariants(["eng"])produces), at least 3 s apart. Works were resolved by author name, as in the issue. The known-languages input was every work the allowed-language query did not match. That is an upper bound on what Bindery sends, since it only asks about works with no default-edition language.book_idbook_idmain: known languages with the_ormain: allowed languages with the_or(from the issue)In the normal case, with no numeric slugs, only the "by slug" queries are sent.
Local checks
go test -p 2 ./cmd/... ./internal/...(no race): okgo test -race ./internal/metadata/hardcover/: okgo vet ./internal/metadata/...: clean.gofmt -l .: empty.golangci-lint v2.11.4 run --concurrency 2 ./internal/metadata/...: 0 issues. I built and ran it with Go 1.26.9, the toolchain CI uses, because a v2.11.4 binary built with Go 1.27 can't read 1.27 export data.internal/metadata/...tests pass under both Go 1.26.9 and 1.27.1.Checklist
Signed-off-bythat matches its author (git commit -s)changelog.d/3333-hardcover-language-evidence-timeout.mddocs/DEPLOYMENT.mdupdated if env vars, config, or upgrade path changed (not applicable: none changed)docs/updated if user-facing behaviour changed (not applicable: the User Guide's "checks Hardcover's editions for each author work in one batched request" still holds for slug-named works)Test plan
go test ./cmd/... ./internal/...cd web && npm run build: not run, becauseweb/is untouched🤖 Generated with Claude Code