lionsoul2014/ip2region · warning · Exception
SearcherPool is closing
Error message
SearcherPool is closing
What it means
SearcherPool.borrow waits (5 ms at a time) for a free Searcher, but if the pool is shutting down (closing flag set) it stops waiting and throws 'SearcherPool is closing'. This prevents lookups from starting during shutdown and from being stranded without ever being returned.
Source
Thrown at binding/cangjie/src/service/searcher_pool.cj:49
}
// borrow takes a Searcher from the pool, blocking until one is available.
// Throws if the pool is closing or closed.
public func borrow(): Searcher {
while (!this.closing.load()) {
if (this.semaphore.tryAcquire(amount: 1)) {
let opt = this.queue.remove()
if (opt.isNone()) {
this.semaphore.release(amount: 1)
continue
}
let s = opt.getOrThrow()
this.loanCnt.fetchAdd(1)
return s
}
sleep(Duration.millisecond * 5)
}
throw Exception("SearcherPool is closing")
}
// return_ returns a Searcher to the pool, or closes it if the pool is shutting down.
public func return_(searcher: Searcher) {
if (this.closing.load()) {
searcher.close()
} else {
this.queue.add(searcher)
this.semaphore.release(amount: 1)
}
this.loanCnt.fetchSub(1)
}
// close closes the pool with a default 10 second timeout.
public func close() {
this.closeTimeout(Duration.second * 10)
}
View on GitHub (pinned to c1a1fc7d59)
Solutions
- Check the pool's closing state (or coordinate with a lifecycle flag) before borrowing
- Stop accepting new work and drain in-flight requests before calling close on the pool
- Catch this exception and fail the request gracefully (e.g. 503) during shutdown
- Delay pool.close() until all workers that borrow have exited
Example fix
// before
let s = pool.borrow() // may throw during shutdown
// after
if (pool.isClosing()) { return ErrorResponse(503, "shutting down") }
let s = pool.borrow() Defensive patterns
Strategy: try-catch
Validate before calling
// Cangjie: skip borrow when shutting down
if (pool.closing.load()) { return Response(503, "shutting down") } Try / catch
try {
let s = pool.borrow()
// ... lookup ...
pool.return_(s)
} catch (e: Exception) {
if (e.message == "SearcherPool is closing") { return Response(503, "shutting down") }
throw e
} Prevention
- Drain in-flight requests before closing the pool
- Expose and check a shutting-down flag in request handlers
- Return searchers promptly via return_ so borrows do not block near shutdown
- In tests, close the pool only after all lookup goroutines/tasks finish
When it happens
Trigger: Calling borrow() concurrently with close()/shutdown of the pool; a long shutdown overlapping in-flight request handling; closing the pool while a burst of borrows is still queued.
Common situations: Graceful server shutdown racing with late HTTP requests, health-check probes firing during process termination, test teardown issuing one more lookup after pool.close().
Related errors
- incomplete read (${rBytes} read, ${stats.size} expected)
- searchers must be > 0
- xdb file IP version mismatch: expected ${ipVersion.name}, go
AI-assisted analysis of lionsoul2014/ip2region@c1a1fc7d59 (2026-09-02).
Data as JSON: /api/errors/679502f5eb195388.
Report an issue: GitHub.