Skip to content

Fix non-blocking jobs losing running operations on insert failure - #254

Open
rubensworks wants to merge 1 commit into
master-1.21-ltsfrom
fix-nonblocking-insert-failure
Open

rubensworks wants to merge 1 commit into
master-1.21-ltsfrom
fix-nonblocking-insert-failure

Conversation

@rubensworks

Copy link
Copy Markdown
Member

Related to the non-blocking problem described in #252 (comment) (crafting results stop being registered for big non-blocking crafts, until the interface is replaced).

Problem

When a target accepts the recipe inputs in simulation, but refuses part of them for real, consumeAndInsertCrafting called unmarkCraftingJobProcessing. That dropped all pending output entries of the job, including operations that were already running in the machine in non-blocking mode. Their results were then no longer claimed. On top of that, the refused inputs were put into the storage network instead of back into the job, so the job's buffer was short and the job stayed pending forever.

This mismatch between simulation and real insertion happens easily in non-blocking mode, as that fills machines up to capacity: inputs are simulated one by one, so two equal instances that each fit separately (for example 1 free spot left) are accepted in simulation, while only one fits for real. Blocking mode rarely fills a machine, which matches the report that blocking mode works.

Changes

  • When simulating insertion, equal instances are stacked first, so simulation fails if they only fit separately. Real insertion is unchanged.
  • On a real insertion failure, only the failed operation is undone. Other running operations of the job stay tracked, and the job returns to the queue once none are running.
  • Refused inputs go back into the job's buffer instead of the storage network. (A new CraftingHelpers.insertCrafting overload takes a fallback storage getter. The existing signature still falls back to the network.)
  • The observers are only unregistered if the failed operation was still pending, so the observer counter can not be decremented twice for one operation.

Known limitation: inputs that did get into the machine during a failed insertion can not be taken back, so the job can still end up short on inputs in that case. The added stacking avoids the most common cause of such failures.

Tests

New game tests in GameTestsItemsCraftNonBlockingInsertFailure:

  • testNonBlockingJobFinishesWhenTargetFillsUp: two equal inputs, machine with 3 free spots. Without the fix, the job gets stuck at amount=2 with an empty buffer.
  • testNonBlockingJobKeepsRunningOperationsWhenInsertionFails: two different unstackable inputs competing for the last free slot. Checks that the running operation is still counted and the refused input goes back to the job, not to storage.

Both fail without the production changes and pass with them. ./gradlew build and ./gradlew runGameTestServer (84 tests) pass.


Generated by Claude Code

When a target accepted recipe inputs in simulation but not for real,
all running operations of the job were forgotten, and the refused
inputs were moved to the storage network. In non-blocking mode, this
made crafting jobs get stuck forever.

Equal inputs are now stacked when simulating, so simulation also fails
when they only fit separately. If the real insertion still fails, only
that operation is undone, and the refused inputs go back to the job.

Related to #252

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D8EZpiK75euMoLjy5r6suM
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.

2 participants