Skip to content

Conversation

Arkatufus
Copy link
Contributor

Cherry-picked from commit bf44386

  • Force synchronous start for TestActor

fix #7770

  • separate creation of implicit, default TestActor from additional ones

  • force TestActor to start via CTD tweak instead

  • don't wait for TestActor to start

  • Revert "don't wait for TestActor to start"

This reverts commit bdd77f9.

  • run default TestActor without CallingThreadDispatcher

  • fix TestKit deadlock during parallel test execution

This commit resolves a deadlock that occurs when running tests in parallel, where the initial TestActor creation gets stuck during async initialization with CallingThreadDispatcher.

The root cause was that SystemActorOf hardcodes async=true initialization, creating a RepointableActorRef that requires processing a Supervise system message. With CallingThreadDispatcher, this creates a circular dependency:

  • TestKit constructor blocks waiting for TestActor initialization
  • CallingThreadDispatcher only runs on the calling thread
  • The calling thread is blocked, so Supervise message never gets processed

The solution bypasses SystemActorOf and directly calls AttachChild with async=false, enabling true synchronous initialization while preserving full system integration including supervision tree and mailbox configuration.

This maintains compatibility with CallingThreadDispatcher for deterministic testing while eliminating startup deadlocks in parallel test scenarios.

Resolves issue where TestProbe child actor creation and implicit sender functionality would fail due to incomplete TestActor initialization.

  • Fix TestKit serialization issue
  • Use AttachChild with isSystemService=true to exempt TestActor from serialization verification
  • Resolves 700+ test failures caused by UnboundedChannelWriter serialization errors
  • still working on synchronous TestActor startup

  • Fix TestKit deadlock during parallel test execution

Resolves deadlock that occurs when TestKit instances are created in parallel and actors try to interact with TestActor during initialization. The issue was caused by CallingThreadDispatcher creating RepointableActorRef which requires async initialization, leading to deadlocks.

Changes:

  • Add AttachChildWithAsync internal method to ActorCell to control sync/async actor creation
  • Modify TestKitBase to create TestActor synchronously (LocalActorRef) instead of async (RepointableActorRef)
  • Update Xunit/Xunit2 TestKits to create logger actors synchronously
  • Replace Ask with Tell for logger initialization to avoid synchronous wait deadlocks
  • Add InternalsVisibleTo for Xunit TestKits to access internal Akka methods
  • Maintain LoggerInitialized response for protocol compatibility (has IDeadLetterSuppression)

Fixes #7770

  • added API approvals

  • remove EnsureTestActorReady method

  • API approvals

  • ensure calls can't get contaminated with references

  • fix API approvals

  • Fix race condition in ParallelTestActorDeadlockSpec

The test had a race condition where the PingerActor sends 'ping' to TestActor during PreStart, but the test was expecting 'test-message' first. This could cause ExpectMsgAsync to receive the wrong message and fail.

Fixed by properly expecting the 'ping' message first before sending and expecting the 'test-message'.

* Force synchronous start for `TestActor`

fix akkadotnet#7770

* separate creation of implicit, default `TestActor` from additional ones

* force `TestActor` to start via CTD tweak instead

* don't wait for `TestActor` to start

* Revert "don't wait for `TestActor` to start"

This reverts commit bdd77f9.

* run default `TestActor` without `CallingThreadDispatcher`

* fix TestKit deadlock during parallel test execution

This commit resolves a deadlock that occurs when running tests in parallel, where the initial TestActor creation gets stuck during async initialization with CallingThreadDispatcher.

The root cause was that SystemActorOf hardcodes async=true initialization, creating a RepointableActorRef that requires processing a Supervise system message. With CallingThreadDispatcher, this creates a circular dependency:
- TestKit constructor blocks waiting for TestActor initialization
- CallingThreadDispatcher only runs on the calling thread
- The calling thread is blocked, so Supervise message never gets processed

The solution bypasses SystemActorOf and directly calls AttachChild with async=false, enabling true synchronous initialization while preserving full system integration including supervision tree and mailbox configuration.

This maintains compatibility with CallingThreadDispatcher for deterministic testing while eliminating startup deadlocks in parallel test scenarios.

Resolves issue where TestProbe child actor creation and implicit sender functionality would fail due to incomplete TestActor initialization.

* Fix TestKit serialization issue

- Use AttachChild with isSystemService=true to exempt TestActor from serialization verification
- Resolves 700+ test failures caused by UnboundedChannelWriter serialization errors

* still working on synchronous `TestActor` startup

* Fix TestKit deadlock during parallel test execution

Resolves deadlock that occurs when TestKit instances are created in parallel
and actors try to interact with TestActor during initialization. The issue
was caused by CallingThreadDispatcher creating RepointableActorRef which
requires async initialization, leading to deadlocks.

Changes:
- Add AttachChildWithAsync internal method to ActorCell to control sync/async actor creation
- Modify TestKitBase to create TestActor synchronously (LocalActorRef) instead of async (RepointableActorRef)
- Update Xunit/Xunit2 TestKits to create logger actors synchronously
- Replace Ask with Tell for logger initialization to avoid synchronous wait deadlocks
- Add InternalsVisibleTo for Xunit TestKits to access internal Akka methods
- Maintain LoggerInitialized response for protocol compatibility (has IDeadLetterSuppression)

Fixes akkadotnet#7770

* added API approvals

* remove `EnsureTestActorReady` method

* API approvals

* ensure  calls can't get contaminated with  references

* fix API approvals

* Fix race condition in ParallelTestActorDeadlockSpec

The test had a race condition where the PingerActor sends 'ping' to TestActor
during PreStart, but the test was expecting 'test-message' first. This could
cause ExpectMsgAsync to receive the wrong message and fail.

Fixed by properly expecting the 'ping' message first before sending and
expecting the 'test-message'.
@Aaronontheweb Aaronontheweb merged commit 0bfe2fc into akkadotnet:v1.5 Aug 21, 2025
8 of 11 checks passed
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