Skip to content

Fix test hangs by async shutdown#55

Open
zamderax wants to merge 5 commits intoapache:masterfrom
wendylabsinc:fix/test-hanging-issue
Open

Fix test hangs by async shutdown#55
zamderax wants to merge 5 commits intoapache:masterfrom
wendylabsinc:fix/test-hanging-issue

Conversation

@zamderax
Copy link
Contributor

@zamderax zamderax commented Nov 30, 2025

I added an sync shutdown helpers for NIO thread pools and event loop groups

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR attempts to fix test hangs by replacing synchronous syncShutdownGracefully() calls with new async shutdown helper functions. The change affects how NIO EventLoopGroups and ThreadPools are cleaned up in test teardown.

  • Introduces two new helper functions: shutdownEventLoopGroupAsync() and shutdownThreadPoolAsync()
  • Replaces all try? elg.syncShutdownGracefully() and try? pool.syncShutdownGracefully() calls with the new async helpers
  • Refactors MemoryAdapterAsyncTests to use a withAdapter helper that manages EventLoopGroup lifecycle

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
Tests/CasbinTests/TestSupport.swift Adds Dispatch import and two new async shutdown helper functions that use fire-and-forget pattern with background queue
Tests/CasbinTests/RbacApiTests.swift Updates defer block in withEnforcer to use new async shutdown helpers instead of sync shutdown
Tests/CasbinTests/MemoryAdapterAsyncTests.swift Refactors from makeAdapter() to withAdapter() helper pattern and updates to use async shutdown in defer block
Tests/CasbinTests/EnforcerTests.swift Updates defer block in withELGAndPool to use new async shutdown helpers instead of sync shutdown
Tests/CasbinTests/ConfigTests.swift Updates defer blocks in both test methods to use new async shutdown helpers instead of sync shutdown

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

func tryBool(_ body: () throws -> Bool) -> Bool { (try? body()) ?? false }

// Non-blocking shutdown helpers so cooperative test executors don't hang.
func shutdownEventLoopGroupAsync(_ group: EventLoopGroup) {
Copy link

Copilot AI Nov 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The function name shutdownEventLoopGroupAsync is misleading. In Swift async/await conventions, "async" typically refers to async functions that use structured concurrency. This function is actually performing a "fire-and-forget" operation. Consider naming it shutdownEventLoopGroupInBackground or beginShutdownEventLoopGroup to better reflect its behavior.

Suggested change
func shutdownEventLoopGroupAsync(_ group: EventLoopGroup) {
func shutdownEventLoopGroupInBackground(_ group: EventLoopGroup) {

Copilot uses AI. Check for mistakes.
@nomeguy
Copy link

nomeguy commented Nov 30, 2025

@zamderax modify based on review: #55 (review)

- Add dedicated async and background shutdown helper functions
- Replace defer blocks with InBackground variants for fire-and-forget cleanup
- Use explicit await for async shutdown in MemoryAdapterAsyncTests
- Prevents test hanging issues by properly managing EventLoopGroup and NIOThreadPool lifecycle
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 5 out of 5 changed files in this pull request and generated 7 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +45 to +47
func shutdownThreadPoolInBackground(_ pool: NIOThreadPool) {
pool.shutdownGracefully(queue: .global()) { _ in }
}
Copy link

Copilot AI Dec 19, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The background shutdown helpers ignore all errors including the completion callback. This could mask critical shutdown failures in tests. Consider logging or asserting on errors during shutdown to catch potential issues during test execution.

Copilot uses AI. Check for mistakes.
let pool = NIOThreadPool(numberOfThreads: 1)
pool.start()
defer { try? pool.syncShutdownGracefully() }
defer { shutdownThreadPoolInBackground(pool) }
Copy link

Copilot AI Dec 19, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using fire-and-forget background shutdown in a defer block may not properly clean up resources before the test completes. The test may exit while shutdown is still in progress, potentially causing resource leaks or test interference. Since these tests appear to be synchronous (not async), consider whether the tests truly hang with syncShutdownGracefully, or if the hang is due to another issue that should be addressed differently.

Copilot uses AI. Check for mistakes.
defer { shutdownThreadPoolInBackground(pool) }
let elg = MultiThreadedEventLoopGroup(numberOfThreads: 1)
defer { try? elg.syncShutdownGracefully() }
defer { shutdownEventLoopGroupInBackground(elg) }
Copy link

Copilot AI Dec 19, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using fire-and-forget background shutdown in a defer block may not properly clean up resources before the test completes. The test may exit while shutdown is still in progress, potentially causing resource leaks or test interference. Since these tests appear to be synchronous (not async), consider whether the tests truly hang with syncShutdownGracefully, or if the hang is due to another issue that should be addressed differently.

Copilot uses AI. Check for mistakes.
func testFromText() throws {
let elg = MultiThreadedEventLoopGroup(numberOfThreads: 1)
defer { try? elg.syncShutdownGracefully() }
defer { shutdownEventLoopGroupInBackground(elg) }
Copy link

Copilot AI Dec 19, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using fire-and-forget background shutdown in a defer block may not properly clean up resources before the test completes. The test may exit while shutdown is still in progress, potentially causing resource leaks or test interference. Since these tests appear to be synchronous (not async), consider whether the tests truly hang with syncShutdownGracefully, or if the hang is due to another issue that should be addressed differently.

Copilot uses AI. Check for mistakes.
nomeguy and others added 3 commits December 20, 2025 11:26
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
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.

3 participants