Base.Semaphore and @spawn: The Illusion of Control vs. Explicit Resource Management

All the best to everyone

The Problem
When using Base.Semaphore to limit the number of concurrently executing heavy tasks, there is a fundamental difference in the behavior of the two approaches:
Option A (Syntactic sugar do):

Base.acquire(sem) do
    data = take!(chan)
    @spawn handle(data)
end

Option B (Explicit acquire/release via closure) in asynchrony:

Base.acquire(sem)
data = take!(chan)
@spawn try 
    handle(data)
finally
    Base.release(sem)
end

Option A works.

Option B, at least in complex hybrid parallelization schemes, leads to erratic semaphore behavior and stalling.

And I can’t understand whether this is a bug or whether option A is ideologically and/or practically the only correct one?