hengebytes/webservice-core-async-bundle
Adds asynchronous web service request handling to Hengebytes WebService Core. It lets PHP applications dispatch concurrent calls without blocking, helping integrate slow or multiple remote services more efficiently while keeping core client workflows intact.
This package serializes concurrent requests that share a cache entry: the first request does the expensive work (e.g. a slow SOAP/HTTP call), and any request that hits the lock waits, then reloads the now-populated response instead of repeating the call. v1.3.11 is primarily a correctness release for that wait-and-reload path, so if you are adopting it fresh, you are starting from the first version where the reload is trustworthy.
Minimal steps:
LockResponseLoaderResponseModifier, ReloadLockedResponseResponseModifier) in your request pipeline. Both rely on the container autowiring the MonologLogHandler; it resolves to null when logging is disabled, so you do not need to guard for that case.logs/lock_wait_threshold (default 5s). This is the only knob the release adds, and it controls when lock contention becomes visible.First use case: wrap a single expensive upstream call behind a cache lock keyed by request identity, and confirm that a second concurrent request returns the first request's payload rather than a 423 placeholder.
Where to look first: CacheManager::awaitUnlock() (now returns the seconds waited as a float) is the cleanest instrumentation point, and ReloadLockedResponseResponseModifier::reloadLockedResponse() is the new public static entry point if you need to drive the reload yourself.
Cache-lock scoping. Key the lock to the exact upstream call identity (URL + normalized body/params). Over-broad keys serialize unrelated traffic; over-narrow keys collapse nothing and you pay the lock cost for zero benefit.
Instrument the wait. awaitUnlock() returning a float lets you emit a metric or span attribute per wait without parsing logs. Prefer this for dashboards and reserve the log warning for alerting.
Customize the action name. Lock waits are logged as <customAction>:lock_wait. Set a per-endpoint action so a grep tells you which upstream is contended, not just that something waited.
Treat 423 as an internal signal. The placeholder (423 {"cacheId": ...}) is never returned to the caller as a successful response in this version. If your error mapping sees a 423 with a cacheId body from anywhere else (older node, proxy), map it to a retry, never to a user-facing success.
Surface real failures. Errors from the reloaded request now propagate with their original cause. Wrap the pipeline call in a try/catch and translate to your API's error shape — you will now get the actual exception rather than a swallowed transport error, so your existing catch blocks may start matching more than they used to.
Rely on lock release for retries. A failure in store-to-cache (TTL callback, tag assignment) or any Throwable before a response exists releases the lock immediately. That makes "fail fast, retry" safe: you will not sit behind a 60s TTL.
Custom pipeline. If you are building your own middleware stack (as soap-core-async-bundle v2.0.1 does), call ReloadLockedResponseResponseModifier::reloadLockedResponse() so the reloaded response goes through its own pipeline rather than being consumed as a raw response.
awaitUnlock() changed from void to float. Ignoring the return value is fine. Subclassing CacheManager or implementing an interface that declares void is not — that is your one real breaking change.LockResponseLoaderResponseModifier gained an optional constructor argument. Container autowiring handles it, but manual instantiation in tests or factories needs null passed explicitly when logging is off.logs/lock_wait_threshold to 0.1s will flood logs with normal jitter. Set it just above your p95 upstream latency.awaitUnlock() return value.:lock_wait; confirm the log/store/unlock middleware appear in the reloaded request's pipeline; confirm no 423 bodies reach clients; confirm a thrown exception mid-request leaves no residual lock (check awaitUnlock() return time on the next request).How can I help you explore Laravel packages today?