Reuse synthesis objects and WebSocket connections with object pools, and configure concurrency, warm-up, and error handling to reduce connection overhead.
Scope
Object pools retain synthesis objects and their WebSocket connections to reduce object creation, TCP/TLS handshakes, and protocol upgrades. The following model series and SDKs support object pooling:
- Qwen-Audio-TTS, CosyVoice: Python and Java object pools.
Prerequisites
- Get an API key and set
DASHSCOPE_API_KEY. Use a key for the region you call. - Replace
{WorkspaceId}with the region’s workspace ID and configure its WebSocket endpoint.
- Python SDK
- Java SDK
Qwen-Audio-TTS and CosyVoice object pooling requires DashScope Python SDK 1.25.2 or later:
Configure concurrency and resource pools
Configure resource pools for the expected number of simultaneous tasks and server capacity. Model limits apply to the Alibaba Cloud account and are shared by its RAM users, workspaces, and API keys. For model request-rate and concurrency limits, see Rate limits.
- Start with a pool capacity of 1.5–2 times peak concurrency and adjust for the actual workload.
- The Python pool may create extra objects when all pooled objects are borrowed. These objects need new connections when used.
- Java settings
- Server configuration reference
Set SDK environment variables before starting the Java process. The first three variables are SDK settings; the pool capacity variables below them are defined by the examples:
The Java examples set
| Environment variable | Default | Description |
|---|---|---|
DASHSCOPE_CONNECTION_POOL_SIZE | 32 | The underlying OkHttp idle connection pool setting. |
DASHSCOPE_MAXIMUM_ASYNC_REQUESTS | 32 | The maximum requests setting for the underlying asynchronous dispatcher. |
DASHSCOPE_MAXIMUM_ASYNC_REQUESTS_PER_HOST | 32 | The per-host maximum requests setting for the underlying asynchronous dispatcher. |
COSYVOICE_OBJECTPOOL_SIZE | 500 | Object pool capacity in the Qwen-Audio-TTS/CosyVoice Java example, used for maxTotal and maxIdle. This is not a built-in SDK parameter. |
maxIdle equal to maxTotal to reduce object recreation after idle objects are destroyed. Close an object’s connection when destroying it. At maxTotal, new borrow requests wait for an available object.Code examples
Qwen-Audio-TTS/CosyVoice
The examples use qwen-audio-3.1-tts-flash and longanhuan_v3.1 for three concurrent synthesis tasks. For CosyVoice, change the model and voice to cosyvoice-v3-flash and longanyang. For other models and voice requirements, see Real-time speech synthesis.
- Python SDK
- Java SDK
Production use
Resource management
- Configure the API key and endpoint, then create a shared object pool for application tasks.
- Borrow and configure an object. In Python, pass the model, voice, format, and callback to
borrow_synthesizer. In the Qwen-Audio-TTS/CosyVoice Java example, callborrowObject, then callupdateParamAndCallback(param, callback)every time to set the parameters and callback for that task. - Run synthesis. Qwen-Audio-TTS/CosyVoice objects support
callorstreaming_callin Python, andcallorstreamingCallin Java. - After normal completion, return the object with
return_synthesizerin Python orreturnObjectin Java. Do not directly return unfinished or failed objects: call the object'sclose()in Python, or discard it withinvalidateObjectin Java and let the factory close its connection. - After all tasks finish, release pool resources with
shutdown()in Python or the pool'sclose()in Java.
Authentication and multiple API keys
- The API key is sent in the
Authorizationheader only during the WebSocket handshake. Laterrun-taskmessages do not carry it. Changing a key in parameters or global configuration does not change an existing connection's identity, which can assign identity, quota usage, or charges differently from what you expect. - In Python, set
dashscope.api_keybefore creating the pool. Connections established during initialization retain the handshake key, andborrow_synthesizerhas no API key parameter.SpeechSynthesizerObjectPoolis a process-wide singleton, so isolate different keys in different processes. - In Java, create a separate pool for each API key and use the same key throughout each pool. For Qwen-Audio-TTS/CosyVoice, call
updateParamAndCallbackeach time an object is borrowed. This method does not reauthenticate an existing connection.
Warm-up and latency measurement
- After startup or network recovery, run warm-up calls and increase concurrency gradually. Before performance testing, warm up at the target concurrency, for example for 1–2 minutes, and collect measurements once connections are being reused steadily.
- The Python pool establishes connections during initialization. Java
GenericObjectPoolcreates objects on demand and connects on the first synthesis call, so warming up Java connections requires actual synthesis requests. - The first call includes WebSocket connection overhead. Measure its first-audio latency and total task time separately from calls that reuse a connection. You can also use the real-time factor (RTF, total synthesis time / audio duration) to evaluate synthesis speed.
- For Qwen-Audio-TTS, CosyVoice, connections close after 60 seconds of inactivity following task completion. Evaluate the next call after a long idle period as a new connection.
get_first_package_delay() for first-audio latency and get_last_request_id() for the request ID used to correlate request logs. Java objects provide getLastRequestId() for the request ID.
Troubleshooting
TCP connections keep increasing despite steady traffic
Frequently creating synthesis objects without closing old connections can continually increase connection counts and server resource usage. Check that objects are returned after task completion and unused connections are closed.
In Java, when maxIdle is less than maxTotal, returned objects above the idle capacity are destroyed. If the factory's destroyObject does not close the WebSocket, the connection may remain open after the object is destroyed. Set maxIdle equal to maxTotal to reduce repeated destruction and creation, and close connections whenever objects are destroyed.
Tasks incur extra waiting time or time out
At maxTotal, borrowing from a Java object pool waits for an available object. Check pool capacity, object returns, and connection cleanup to avoid extra time spent waiting for objects.
Tasks slow down after startup or network recovery
After startup or network recovery, run warm-up calls and increase concurrency gradually to avoid blocking on many simultaneous WebSocket handshakes.
The server returns Invalid action('run-task')! Please follow the protocol!
After a client error interrupts a task, the server may still consider the previous task active. Reusing that connection for a new run-task causes a protocol sequence error. Close the connection and discard the object, then establish a new connection for later tasks.
Calls spike despite steady application traffic
Mass reconnection after startup, network interruptions, or many server errors can cause tasks to accumulate. When connections recover, simultaneous submission of those tasks can create a spike and trigger account limits.
- Check for network problems or many server errors before the spike, such as
Requests rate limit exceeded, please try again later.. - Control concurrency during startup and recovery. In Java,
maxTotallimits the number of objects borrowed simultaneously from the same pool. - Check account quotas. To request an increase, follow the procedure in Rate limits.
- Adjust server specifications or add servers for the actual workload.