Common pitfalls
Common C++ API misuse patterns, why they fail, and how to fix them.
This page describes two important usage rules of the Blazeauth C++ API. Both are easy to violate when mixing synchronous and asynchronous code.
Rules first
Do not call sync API inside async callbacks
Async callbacks run on the library I/O thread. Inside async callbacks, call only other async methods.
Do not destroy session inside its own async callbacks
Do not let the last owning blaze::session instance die inside one of its
own async callbacks. Destroy it only after control returns to your own thread.
Do not call synchronous API inside async callbacks
Async callbacks are executed on the library I/O thread. Synchronous API calls internally wait for async completion, so calling a sync method from that same thread would block the thread that must deliver the result.
Because of that, the library rejects such calls with std::errc::operation_would_block.
What happens
- Throwing sync overloads throw
std::system_errorwithstd::errc::operation_would_block. - No-throw sync overloads store
std::errc::operation_would_blockinto the passedstd::error_code.
Why this happens
The synchronous API waits until the async operation completes. If that wait starts from the same I/O thread that must run the callback, the operation cannot make progress correctly.
Wrong
session.async_connect([&session](std::error_code ec, blaze::api_server) {
if (ec) {
return;
}
// Wrong: sync API inside async callback.
blaze::application app = session.initialize("your-api-key", "client-id");
});Correct
session.async_connect([&session](std::error_code ec, blaze::api_server) {
if (ec) {
return;
}
session.async_initialize("your-api-key", "client-id",
[](std::error_code init_ec, blaze::application app) {
if (init_ec) {
return;
}
if (!app.good()) {
return;
}
// Continue with other async calls here.
});
});Safe pattern
If your application prefers synchronous flow, finish the async callback quickly and hand control back to your own thread/executor. Do not switch from async API to sync API while still executing inside the library callback.
Do not destroy the session inside its own async callback
The internal websocket_session object owns the library I/O runtime.
Destroying the last owning blaze::session from one of its own async callbacks
means destruction starts on that same I/O thread.
That is not supported.
What happens
If destruction reaches the internal websocket session on the I/O thread, the library terminates the process.
Why this happens
During destruction, the session must:
- shut down the websocket cleanly;
- invoke shutdown-related cleanup;
- stop the internal I/O runtime;
- wait for the worker thread to finish.
Doing that from the worker thread itself is invalid. It turns destruction into a self-stop/self-join scenario, which the current architecture does not permit. The library therefore treats it as fatal misuse.
Wrong
std::shared_ptr<blaze::session> session = std::make_shared<blaze::session>();
session->async_connect([session](std::error_code ec, blaze::api_server) mutable {
if (ec) {
session.reset();
return;
}
// Wrong: this may destroy the last owner on the library I/O thread.
session.reset();
});Correct
If you need to stop using the session from async code:
- call
async_shutdown(...)if shutdown is needed; - signal your outer code that the async chain is finished;
- destroy/reset the session on your own thread after the callback returns.
#include "blazeauth/api/api.hpp"
#include <future>
#include <memory>
int main() {
std::shared_ptr<blaze::session> session = std::make_shared<blaze::session>();
std::promise<void> done;
std::future<void> result = done.get_future();
session->async_connect([session, &done](std::error_code ec, blaze::api_server) {
if (ec) {
done.set_value();
return;
}
session->async_shutdown([&done](std::error_code) {
done.set_value();
});
});
result.get();
// Safe: destruction happens after callback chain is finished,
// on the caller thread.
session.reset();
return 0;
}Practical rules
- If you start with async API, stay async for the whole callback chain.
- Keep session ownership outside the library callbacks.
- Use async shutdown inside async code.
- Destroy the session only after control has returned to your own thread.