Deploying to Cloudflare Workers
This guide covers deploying the Milvus Node.js SDK to Cloudflare Workers using the HTTP client.
Why HTTP Client for Cloudflare Workers?
Cloudflare Workers only support HTTP/HTTPS protocols and do not support raw TCP connections required by gRPC. Therefore, you must use the HttpClient when deploying to Cloudflare Workers.
Prerequisites
- A Cloudflare account
- Wrangler CLI installed:
npm install -g wrangler - A Milvus instance (self-hosted or Zilliz Cloud)
Installation
Install the SDK in your Cloudflare Workers project:
npm install @zilliz/milvus2-sdk-node
# or
yarn add @zilliz/milvus2-sdk-nodeBasic Setup
1. Create Worker File
Create src/index.js (or worker.js):
import { HttpClient } from '@zilliz/milvus2-sdk-node';
export default {
async fetch(request, env, ctx) {
const client = new HttpClient({
baseURL: env.MILVUS_ENDPOINT,
token: env.MILVUS_TOKEN,
timeout: 25000, // Cloudflare Workers free tier: 30s, paid: up to 15min
});
try {
const url = new URL(request.url);
const path = url.pathname;
// Handle different endpoints
if (path === '/search' && request.method === 'POST') {
const body = await request.json();
const results = await client.search({
collection_name: body.collection_name || 'my_collection',
data: body.vectors,
limit: body.limit || 10,
output_fields: body.output_fields || [],
});
return new Response(JSON.stringify({ results }), {
headers: {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*',
},
});
}
if (path === '/insert' && request.method === 'POST') {
const body = await request.json();
const result = await client.insert({
collection_name: body.collection_name || 'my_collection',
data: body.data,
});
return new Response(JSON.stringify({ result }), {
headers: {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*',
},
});
}
return new Response('Not Found', { status: 404 });
} catch (error) {
console.error('Milvus error:', error);
return new Response(
JSON.stringify({
error: error.message,
status: error.status || 500,
}),
{
status: error.status || 500,
headers: {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*',
},
}
);
}
},
};2. Configure Wrangler
Create wrangler.toml:
name = "milvus-worker"
main = "src/index.js"
compatibility_date = "2024-01-01"
# Environment variables (use secrets for production)
[vars]
# MILVUS_ENDPOINT = "https://your-instance.zillizcloud.com"
# MILVUS_TOKEN = "your-token"
# For production, use secrets instead:
# wrangler secret put MILVUS_ENDPOINT
# wrangler secret put MILVUS_TOKEN
# Worker limits
[limits]
cpu_ms = 50 # CPU time limit in milliseconds3. Set Secrets (Production)
For production, use Wrangler secrets instead of environment variables:
wrangler secret put MILVUS_ENDPOINT
# Enter: https://your-instance.zillizcloud.com
wrangler secret put MILVUS_TOKEN
# Enter: your-api-tokenAdvanced Example: Client Reuse
For better performance, reuse the client instance within the same request context:
import { HttpClient } from '@zilliz/milvus2-sdk-node';
let clientCache = null;
function getClient(env) {
if (!clientCache) {
clientCache = new HttpClient({
baseURL: env.MILVUS_ENDPOINT,
token: env.MILVUS_TOKEN,
timeout: 25000,
});
}
return clientCache;
}
export default {
async fetch(request, env, ctx) {
const client = getClient(env);
// ... rest of your code
},
};Complete Example: Vector Search API
Here’s a complete example for a vector search API:
import { HttpClient } from '@zilliz/milvus2-sdk-node';
export default {
async fetch(request, env) {
// Handle CORS preflight
if (request.method === 'OPTIONS') {
return new Response(null, {
headers: {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'GET, POST, OPTIONS',
'Access-Control-Allow-Headers': 'Content-Type',
},
});
}
const client = new HttpClient({
baseURL: env.MILVUS_ENDPOINT,
token: env.MILVUS_TOKEN,
timeout: 25000,
});
try {
const url = new URL(request.url);
if (url.pathname === '/api/search' && request.method === 'POST') {
const body = await request.json();
if (!body.vector || !body.collection_name) {
return new Response(
JSON.stringify({ error: 'Missing required fields' }),
{
status: 400,
headers: { 'Content-Type': 'application/json' },
}
);
}
const results = await client.search({
collection_name: body.collection_name,
data: [body.vector],
limit: body.limit || 10,
output_fields: body.output_fields || [],
search_params: body.search_params || {},
});
return new Response(JSON.stringify({ results }), {
headers: {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*',
},
});
}
return new Response('Not Found', { status: 404 });
} catch (error) {
console.error('Error:', error);
return new Response(
JSON.stringify({
error: error.message,
status: error.status || 500,
}),
{
status: error.status || 500,
headers: {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*',
},
}
);
}
},
};Deployment
Deploy to Cloudflare Workers
# Login to Cloudflare
wrangler login
# Deploy
wrangler deploy
# Deploy to a specific environment
wrangler deploy --env productionTest Locally
# Start local development server
wrangler dev
# Test with curl
curl -X POST http://localhost:8787/api/search \
-H "Content-Type: application/json" \
-d '{
"collection_name": "my_collection",
"vector": [0.1, 0.2, 0.3],
"limit": 5
}'Timeout Limits
- Free tier: 30 seconds CPU time, 30 seconds wall-clock time
- Paid tier: Up to 15 minutes CPU time, 30 seconds wall-clock time (can be extended)
Set your timeout accordingly:
const client = new HttpClient({
baseURL: env.MILVUS_ENDPOINT,
token: env.MILVUS_TOKEN,
timeout: 25000, // Leave buffer for Worker overhead
});Best Practices
- Use HTTP Client: Cloudflare Workers only support HTTP/HTTPS, not gRPC
- Set appropriate timeouts: Account for Worker execution limits
- Handle errors gracefully: Return proper HTTP status codes
- Use secrets for credentials: Never commit tokens to your repository
- Enable CORS: If calling from browser, set appropriate CORS headers
- Client reuse: Reuse client instances within the same request context
- Monitor performance: Use Cloudflare Analytics to track execution times
Troubleshooting
Error: “gRPC is not supported”
Solution: Use HttpClient instead of MilvusClient.
Error: “Request timeout”
Solution:
- Reduce timeout value to leave buffer for Worker overhead
- Optimize your Milvus queries
- Consider upgrading to paid tier for longer execution times
Error: “Module not found”
Solution: Ensure @zilliz/milvus2-sdk-node is installed and listed in package.json.
Next Steps
- Learn about Vercel Deployment
- Explore AWS Lambda Deployment
- Check out HTTP Client Guide
- Read Best Practices