Skip to content

Register the handle once when minting a DOI - #1601

Open
jrhoads wants to merge 3 commits into
masterfrom
cursor-fix-double-handle-put-da62
Open

jrhoads wants to merge 3 commits into
masterfrom
cursor-fix-double-handle-put-da62

Conversation

@jrhoads

@jrhoads jrhoads commented Oct 1, 2026 •

Copy link
Copy Markdown
Contributor

Purpose

Closes #1295.

Creating a registered/findable DOI through the API (or publishing a draft with a current_user) sent the handle PUT twice. After the first successful PUT, register_url stored minted with a full update. That save opened a new transaction and fired every after_commit again, including update_url, which registered the handle a second time. The nested save also re-ran XML schema validation, bumped version a second time, and enqueued a second index job, all inside the API request.

Approach

Write minted/updated without callbacks, then explicitly re-index once so OpenSearch still receives the registered date.

Key Modifications

  • app/models/concerns/indexable.rb: move the index-dispatch body of the create/update after_commit into a public enqueue_index_update method. The callback calls it, then keeps the Event Data message logic unchanged. Routing (IndexJobDoiRegistration, OtherDoi bulk jobs, inactive-index sync, etc.) is unchanged for every model.
  • app/models/concerns/helpable.rb: on a 200/201 with blank minted, persisted records use update_columns(minted:, updated:) followed by enqueue_index_update; unsaved records use assign_attributes (previously update silently created the record).
  • spec/requests/datacite_dois/post_spec.rb: WebMock-stubbed handle server; asserts exactly one PUT for POST of a findable DOI and for PATCH of a draft with event: "publish", plus registered in the response and minted in the DB.
  • spec/concerns/helpable_spec.rb: persisted DOI with minted: nil gets minted/updated set, version unchanged, no second update_url, one enqueue_index_update; an unsaved DOI gets minted assigned without being saved.
  • spec/requests/reference_repositories_spec.rb, spec/graphql/types/repository_type_spec.rb: clear the cached prefix_response/10.17616 entry on entry and exit. Both files create and destroy prefix 10.17616 in before/after :all, and ProviderPrefix#prefix_id= resolves prefixes via Rails.cache, so whichever file runs second got the destroyed prefix's id and Client#assign_prefix raised on a nil prefix. This order dependency already exists on master (reproduced there in both orders); the new specs above changed parallel_test's file-size grouping and put both files on the same CI node.

Important Technical Details

  • Indexable is included before after_commit :update_url is declared, so the first index job is enqueued before minted is set. The explicit enqueue_index_update replaces the re-index the nested save used to provide; without it registered would be missing in OpenSearch.
  • version now increases by 1 on creation instead of 2. This is cosmetic, but worth knowing for anyone comparing versions before/after.
  • Not affected: HandleJob (fresh record, no current_user) and later updates to an already-minted DOI (already one PUT).
  • The TODO in Doi#update_url (only register when URL/state changed) is left for a separate change.
  • The new request specs fail on master with "expected to execute 1 time but it executed 2 times" and pass with this change.

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)

Reviewer, please remember our guidelines:

  • Be humble in the language and feedback you give, ask don't tell.
  • Consider using positive language as opposed to neutral when offering feedback. This is to avoid the negative bias that can occur with neutral language appearing negative.
  • Offer suggestions on how to improve code e.g. simplification or expanding clarity.
  • Ensure you give reasons for the changes you are proposing.
Open in Web Open in Cursor 

cursoragent and others added 2 commits October 1, 2026 10:07
Extract the index dispatch from Indexable's after_commit into
enqueue_index_update. register_url now writes minted/updated with
update_columns and re-indexes once, instead of a full update that
re-fired update_url and registered the handle a second time.

Co-authored-by: Joseph Rhoads <jrhoads@users.noreply.github.com>
Co-authored-by: Joseph Rhoads <jrhoads@users.noreply.github.com>
ProviderPrefix#prefix_id= looks prefixes up via Rails.cache (memcached,
24h). repository_type_spec and reference_repositories_spec both create
and destroy prefix 10.17616 in before/after :all, so whichever runs
second gets the destroyed record's id from the cache, ProviderPrefix
fails validation, and Client#assign_prefix raises on a nil prefix.
Pre-existing order dependency, surfaced when parallel_test regrouped
spec files onto the same CI node.

Co-authored-by: Joseph Rhoads <jrhoads@users.noreply.github.com>
@jrhoads
jrhoads requested review from a team and a balanced review from Copilot October 1, 2026 12:46

Copilot AI 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.

Copilot review overview

🟢 Approval recommended

The implementation addresses the duplicate registration path and includes focused regression coverage.

Review effort: Balanced
Findings: None

What changed in this PR

Prevents duplicate Handle registration when minting or publishing a DOI while preserving OpenSearch synchronization.

Changes:

  • Persists minting timestamps without triggering callbacks, then explicitly re-indexes.
  • Extracts reusable index dispatch logic.
  • Adds regression tests and clears stale prefix cache entries in affected suites.
File Description
app/​models/​concerns/​helpable.rb Avoids nested saves after registration.
app/​models/​concerns/​indexable.rb Extracts index enqueue logic.
spec/​concerns/​helpable_spec.rb Tests callback-free timestamp persistence.
spec/​requests/​datacite_dois/​post_spec.rb Verifies one Handle request per registration.
spec/​requests/​reference_repositories_spec.rb Clears stale prefix cache state.
spec/​graphql/​types/​repository_type_spec.rb Isolates prefix cache state in GraphQL tests.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

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.

Investigate double calls to handle server (register_url) on doi registration.

4 participants