@ -1,111 +1,176 @@
# Cloudflare Workers with Swarms: Automated Cron Job Agents
# Cloudflare Workers with Swarms: Production AI Agents
Deploy scheduled AI agents on Cloudflare's global edge network for automated stock analysis and healthcare monitoring. This guide focuses on cron job agents that run automatically at scheduled interval s.
Deploy AI agents on Cloudflare's edge network with automatic cron scheduling and real-time data integration. This guide shows a production-ready implementation with both HTTP endpoints and scheduled trigger s.
## Overview
## Architecture Overview
Cloudflare Workers with cron triggers enable automated agent execution for:
The Cloudflare Workers pattern uses two main handlers:
- **Stock Market Analysis** : Daily market reports and trading insights
- ** `fetch()` **: HTTP requests for testing and manual triggers
- **Healthcare Monitoring** : Patient data analysis and alerts
- ** `scheduled()` **: Cron jobs for automated execution
- **Automated Reporting** : Scheduled business intelligence
- **Global Deployment** : Edge computing with zero cold starts
```javascript
export default {
// HTTP handler for manual testing
async fetch(request, env, ctx) {
// Handle web interface and API endpoints
},
// Cron handler for scheduled execution
async scheduled(event, env, ctx) {
ctx.waitUntil(handleStockAnalysis(event, env));
}
};
```
## Quick Setup
## Quick Setup
### 1. Create Worker Project
### 1. Create Worker Project
```bash
```bash
npx create-cloudflare stock-agent worker
npm create cloudflare@latest stock-agent
cd stock-agent
cd stock-agent
```
```
### 2. Configure Cron Schedule
### 2. Configure Cron Schedule
Edit `wrangler.toml` :
Edit `wrangler.jsonc` :
```toml
name = "stock-analysis-agent"
main = "src/index.js"
compatibility_date = "2024-01-01"
[env.production.vars]
SWARMS_API_KEY = "your-api-key-here"
SLACK_WEBHOOK_URL = "optional-slack-webhook"
# Stock market analysis - after market close
```jsonc
[[env.production.triggers.crons]]
{
cron = "0 21 * * MON-FRI" # 9 PM UTC (4 PM EST)
"$schema": "node_modules/wrangler/config-schema.json",
"name": "stock-agent",
# Healthcare monitoring - every 4 hours
"main": "src/index.js",
[[env.production.triggers.crons]]
"compatibility_date": "2025-08-03",
cron = "0 */4 * * * "
"observability": {
"enabled": true
},
"triggers": {
"crons": [
"0 */3 * * * " // Every 3 hours
]
},
"vars": {
"SWARMS_API_KEY": "your-api-key"
}
}
```
```
## Stock Market Analysis Agent
## Complete Minimal Implementation
Automated daily stock analysis after market close:
Create `src/index.js` :
```javascript
```javascript
export default {
export default {
// Cron job handler - runs automatically
// HTTP handler - provides web interface and manual triggers
async fetch(request, env, ctx) {
const url = new URL(request.url);
// Web interface for testing
if (url.pathname === '/') {
return new Response(`
<!DOCTYPE html>
< html >
< head >
< title > Stock Analysis Agent< / title >
< style >
body { font-family: Arial, sans-serif; max-width: 800px; margin: 50px auto; padding: 20px; }
.btn { padding: 10px 20px; background: #007bff ; color: white; border: none; border-radius: 5px; cursor: pointer; }
.status { background: #f0f8f0 ; padding: 10px; border-left: 3px solid #28a745 ; margin: 20px 0; }
.result { background: #f8f9fa ; padding: 15px; border-radius: 5px; margin: 20px 0; white-space: pre-wrap; }
< / style >
< / head >
< body >
< h1 > 📈 Stock Analysis Agent< / h1 >
< div class = "status" > Status: Online ✅< / div >
< button class = "btn" onclick = "triggerAnalysis()" > 🔥 Start Analysis< / button >
< div id = "result" > < / div >
< script >
async function triggerAnalysis() {
document.getElementById('result').innerHTML = 'Running analysis...';
try {
const response = await fetch('/trigger');
const data = await response.json();
document.getElementById('result').innerHTML =
data.result?.success ?
\`✅ Success\\n\\nAnalysis: \\${data.result.analysis}\` :
\`❌ Error: \\${data.result?.error || data.error}\`;
} catch (error) {
document.getElementById('result').innerHTML = \`❌ Failed: \\${error.message}\`;
}
}
< / script >
< / body >
< / html >
`, {
headers: { 'Content-Type': 'text/html' }
});
}
// Manual trigger endpoint
if (url.pathname === '/trigger') {
try {
const result = await handleStockAnalysis(null, env);
return new Response(JSON.stringify({
message: 'Analysis triggered',
timestamp: new Date().toISOString(),
result
}), {
headers: { 'Content-Type': 'application/json' }
});
} catch (error) {
return new Response(JSON.stringify({
error: error.message
}), {
status: 500,
headers: { 'Content-Type': 'application/json' }
});
}
}
return new Response('Not Found', { status: 404 });
},
// Cron handler - runs automatically on schedule
async scheduled(event, env, ctx) {
async scheduled(event, env, ctx) {
ctx.waitUntil(handleStockAnalysis(event, env));
ctx.waitUntil(handleStockAnalysis(event, env));
}
}
};
};
// Main analysis function used by both HTTP and cron triggers
async function handleStockAnalysis(event, env) {
async function handleStockAnalysis(event, env) {
console.log('🚀 Starting stock analysis...');
try {
try {
// Step 1: Fetch real market data from multiple sources
// Step 1: Fetch real market data (using Yahoo Finance - no API key needed)
const marketData = await fetchMarketData(env);
const marketData = await fetchMarketData();
// Step 2: Get market news
// Check if we got valid data
const marketNews = await fetchMarketNews(env);
const validSymbols = Object.keys(marketData).filter(symbol => !marketData[symbol].error);
if (validSymbols.length === 0) {
throw new Error('No valid market data retrieved');
}
// Step 3: Send real data to Swarms agents for analysis
// Step 2: Send to Swarms AI agent s
const swarmConfig = {
const swarmConfig = {
name: "Real-Time Stock Analysis",
name: "Stock Analysis",
description: "Live market data analysis with AI agents",
description: "Real-time market analysi s",
agents: [
agents: [
{
{
agent_name: "Technical Analyst",
agent_name: "Technical Analyst",
system_prompt: `You are a professional technical analyst. Analyze the provided real market data:
system_prompt: \`Analyze the provided stock data:
- Calculate key technical indicators (RSI, MACD, Moving Averages)
- Identify trends and key levels
- Identify support and resistance levels
- Provide trading signals
- Determine market trends and momentum
- Calculate technical indicators
- Provide trading signals and price targets
Format analysis professionally.\`,
Format your analysis professionally with specific price levels.`,
model_name: "gpt-4o-mini",
model_name: "gpt-4o-mini",
max_tokens: 3000,
max_tokens: 15 00,
temperature: 0.2
temperature: 0.2
},
{
agent_name: "Fundamental Analyst",
system_prompt: `You are a fundamental market analyst. Using the provided market news and data:
- Analyze earnings impact and company fundamentals
- Evaluate economic indicators and Fed policy effects
- Assess sector rotation and market sentiment
- Identify value opportunities and risks
Provide investment recommendations with risk assessment.`,
model_name: "gpt-4o-mini",
max_tokens: 3000,
temperature: 0.3
}
}
],
],
swarm_type: "ConcurrentWorkflow",
swarm_type: "SequentialWorkflow",
task: `Analyze the following real market data and news:
task: \`Analyze this market data: \\${JSON.stringify(marketData, null, 2)}\`,
MARKET DATA:
${JSON.stringify(marketData, null, 2)}
MARKET NEWS:
${marketNews}
Provide comprehensive analysis with:
1. Technical analysis with key levels
2. Fundamental analysis with catalysts
3. Trading recommendations
4. Risk assessment
5. Tomorrow's key levels to watch`,
max_loops: 1
max_loops: 1
};
};
@ -118,370 +183,153 @@ Provide comprehensive analysis with:
body: JSON.stringify(swarmConfig)
body: JSON.stringify(swarmConfig)
});
});
if (!response.ok) {
throw new Error(\`Swarms API error: \\${response.status}\`);
}
const result = await response.json();
const result = await response.json();
console.log('✅ Analysis completed');
if (response.ok) {
return {
console.log('✅ Real-time stock analysis completed');
success: true,
console.log('💰 Cost:', result.metadata?.billing_info?.total_cost);
analysis: result.output,
symbolsAnalyzed: validSymbols.length,
cost: result.usage?.billing_info?.total_cost
};
// Send email directly
await sendEmailReport(env, result.output, marketData);
}
} catch (error) {
} catch (error) {
console.error('❌ Real-time stock analysis failed:', error);
console.error('❌ Analysis failed:', error.message);
return {
success: false,
error: error.message
};
}
}
}
}
// Fetch real market data from Alpha Vantage API
// Fetch market data from Yahoo Finance (free, no API key required)
async function fetchMarketData(env ) {
async function fetchMarketData() {
const symbols = ['SPY', 'QQQ', ' AAPL', 'MSFT', 'TSLA', 'NVD A'];
const symbols = ['SPY', 'AAPL', 'MSFT', 'TSLA'];
const marketData = {};
const marketData = {};
for (const symbol of symbols) {
const promises = symbols.map(async (symbol) => {
try {
try {
// Get daily prices
const controller = new AbortController();
const priceResponse = await fetch(
const timeout = setTimeout(() => controller.abort(), 8000);
`https://www.alphavantage.co/query?function=TIME_SERIES_DAILY&symbol=${symbol}&apikey=${env.STOCK_API_KEY}`
);
const priceData = await priceResponse.json();
// Get technical indicators (RSI)
const rsiResponse = await fetch(
`https://www.alphavantage.co/query?function=RSI&symbol=${symbol}&interval=daily&time_period=14&series_type=close&apikey=${env.STOCK_API_KEY}`
);
const rsiData = await rsiResponse.json();
if (priceData['Time Series (Daily)'] & & rsiData['Technical Analysis: RSI']) {
const latestDate = Object.keys(priceData['Time Series (Daily)'])[0];
const latestPrice = priceData['Time Series (Daily)'][latestDate];
const latestRSI = Object.values(rsiData['Technical Analysis: RSI'])[0];
marketData[symbol] = {
price: parseFloat(latestPrice['4. close']),
open: parseFloat(latestPrice['1. open']),
high: parseFloat(latestPrice['2. high']),
low: parseFloat(latestPrice['3. low']),
volume: parseInt(latestPrice['5. volume']),
change: parseFloat(latestPrice['4. close']) - parseFloat(latestPrice['1. open']),
change_percent: ((parseFloat(latestPrice['4. close']) - parseFloat(latestPrice['1. open'])) / parseFloat(latestPrice['1. open']) * 100).toFixed(2),
rsi: parseFloat(latestRSI?.RSI || 50),
date: latestDate
};
}
// Rate limiting - Alpha Vantage allows 5 requests per minute on free tier
await new Promise(resolve => setTimeout(resolve, 12000));
} catch (error) {
const response = await fetch(
console.error(`Error fetching data for ${symbol}:`, error);
\`https://query1.finance.yahoo.com/v8/finance/chart/\\${symbol}\`,
marketData[symbol] = { error: 'Failed to fetch data' };
{
}
signal: controller.signal,
headers: { 'User-Agent': 'Mozilla/5.0' }
}
}
return marketData;
}
// Fetch market news from Financial Modeling Prep (free tier available)
async function fetchMarketNews(env) {
try {
const newsResponse = await fetch(
`https://financialmodelingprep.com/api/v3/stock_news?tickers=AAPL,MSFT,TSLA,NVDA&limit=10&apikey=${env.FMP_API_KEY || 'demo'}`
);
);
const newsData = await newsResponse.json();
clearTimeout(timeout);
if (Array.isArray(newsData)) {
return newsData.slice(0, 5).map(article => ({
title: article.title,
text: article.text?.substring(0, 300) + '...',
publishedDate: article.publishedDate,
symbol: article.symbol,
url: article.url
}));
}
} catch (error) {
console.error('Error fetching news:', error);
}
return "Market news temporarily unavailable";
if (!response.ok) throw new Error(\`HTTP \\${response.status}\`);
}
// Send email report using Mailgun API
const data = await response.json();
async function sendEmailReport(env, analysis, marketData) {
const result = data.chart.result[0];
// Extract key market movers for email subject
const meta = result.meta;
const movers = Object.entries(marketData)
.filter(([symbol, data]) => data.change_percent & & Math.abs(parseFloat(data.change_percent)) > 2)
.map(([symbol, data]) => `${symbol}: ${data.change_percent}%` )
.join(', ');
const emailSubject = `📊 Daily Stock Analysis - ${new Date().toLocaleDateString()}` ;
const emailBody = `
< h2 > Daily Market Analysis Report< / h2 >
< p > < strong > Date:< / strong > ${new Date().toLocaleString()}< / p >
< p > < strong > Key Market Movers:< / strong > ${movers || 'Market stable'}< / p >
< h3 > AI Agent Analysis:< / h3 >
< div style = "background-color: #f5f5f5 ; padding: 20px; border-radius: 5px;" >
< pre style = "white-space: pre-wrap;" > ${analysis}< / pre >
< / div >
< h3 > Market Data Summary:< / h3 >
< table border = "1" style = "border-collapse: collapse; width: 100%;" >
< tr style = "background-color: #e0e0e0 ;" >
< th > Symbol< / th > < th > Price< / th > < th > Change %< / th > < th > Volume< / th > < th > RSI< / th >
< / tr >
${Object.entries(marketData).map(([symbol, data]) => `
< tr >
< td > ${symbol}< / td >
< td > $${data.price?.toFixed(2) || 'N/A'}< / td >
< td style = "color: ${parseFloat(data.change_percent) >= 0 ? 'green' : 'red'}" >
${data.change_percent}%
< / td >
< td > ${data.volume?.toLocaleString() || 'N/A'}< / td >
< td > ${data.rsi?.toFixed(1) || 'N/A'}< / td >
< / tr >
`).join('')}
< / table >
< p > < em > Generated by Swarms AI Agent System< / em > < / p >
`;
// Send via Mailgun
const formData = new FormData();
formData.append('from', `Stock Analysis Agent <noreply@${env.MAILGUN_DOMAIN}>` );
formData.append('to', env.RECIPIENT_EMAIL);
formData.append('subject', emailSubject);
formData.append('html', emailBody);
try {
const currentPrice = meta.regularMarketPrice;
const response = await fetch(`https://api.mailgun.net/v3/${env.MAILGUN_DOMAIN}/messages`, {
const previousClose = meta.previousClose;
method: 'POST',
const change = currentPrice - previousClose;
headers: {
const changePercent = ((change / previousClose) * 100).toFixed(2);
'Authorization': `Basic ${btoa(` api:${env.MAILGUN_API_KEY}`)}`
},
body: formData
});
if (response.ok) {
return [symbol, {
console.log('✅ Email report sent successfully');
price: currentPrice,
} else {
change: change,
console.error('❌ Failed to send email:', await response.text());
change_percent: changePercent,
}
volume: meta.regularMarketVolume,
} catch (error) {
currency: meta.currency
console.error('❌ Email sending error:', error);
}];
}
}
async function sendSlackNotification(webhookUrl, analysis) {
} catch (error) {
await fetch(webhookUrl, {
return [symbol, { error: error.message }];
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
text: "📈 Daily Stock Market Analysis",
blocks: [{
type: "section",
text: {
type: "mrkdwn",
text: `*Market Analysis Complete*\n\` \`\`${analysis.substring(0, 500)}...\`\`\``
}
}
}]
})
});
});
}
```
## Healthcare Monitoring Agent
Automated patient monitoring and health alerts:
const results = await Promise.allSettled(promises);
results.forEach((result) => {
```javascript
if (result.status === 'fulfilled' & & result.value) {
export default {
const [symbol, data] = result.value;
async scheduled(event, env, ctx) {
marketData[symbol] = data;
// Determine which agent to run based on cron schedule
const hour = new Date().getHours();
if (hour % 4 === 0) {
// Every 4 hours - patient monitoring
ctx.waitUntil(handlePatientMonitoring(event, env));
}
}
}
};
async function handlePatientMonitoring(event, env) {
const healthcareSwarm = {
name: "Patient Monitoring System",
description: "Automated patient health analysis and alerting",
agents: [
{
agent_name: "Vital Signs Analyst",
system_prompt: `Analyze patient vital signs data for abnormalities:
- Heart rate patterns and irregularities
- Blood pressure trends
- Oxygen saturation levels
- Temperature variations
Flag critical conditions requiring immediate attention.`,
model_name: "gpt-4o-mini",
max_tokens: 2000,
temperature: 0.1
},
{
agent_name: "Risk Assessment Specialist",
system_prompt: `Evaluate patient risk factors and health trends:
- Medication interactions
- Chronic condition management
- Recovery progress assessment
- Early warning signs detection
Prioritize patients needing urgent care.`,
model_name: "gpt-4o-mini",
max_tokens: 2000,
temperature: 0.2
}
],
swarm_type: "ConcurrentWorkflow",
task: "Analyze current patient monitoring data and generate health status alerts for medical staff.",
max_loops: 1
};
try {
const response = await fetch('https://api.swarms.world/v1/swarm/completions', {
method: 'POST',
headers: {
'x-api-key': env.SWARMS_API_KEY,
'Content-Type': 'application/json'
},
body: JSON.stringify(healthcareSwarm)
});
});
const result = await response.json();
return marketData;
if (response.ok) {
console.log('🏥 Health monitoring completed');
// Send email alerts for all monitoring results
await sendHealthEmailAlert(env, result.output);
}
} catch (error) {
console.error('❌ Health monitoring failed:', error);
}
}
}
```
// Send healthcare email alerts
## Key Features Explained
async function sendHealthEmailAlert(env, analysis) {
const severity = extractSeverity(analysis);
const isUrgent = severity === 'critical' || severity === 'urgent';
const emailSubject = `${isUrgent ? '🚨 URGENT' : '🏥'} Health Monitoring Alert - ${new Date().toLocaleString()}` ;
const emailBody = `
< h2 style = "color: ${isUrgent ? 'red' : 'blue'};" > Patient Monitoring Report< / h2 >
< p > < strong > Timestamp:< / strong > ${new Date().toLocaleString()}< / p >
< p > < strong > Severity Level:< / strong > < span style = "color: ${getSeverityColor(severity)}; font-weight: bold;" > ${severity.toUpperCase()}< / span > < / p >
< h3 > AI Health Analysis:< / h3 >
< div style = "background-color: ${isUrgent ? '#ffe6e6' : '#f0f8ff'}; padding: 20px; border-radius: 5px; border-left: 5px solid ${isUrgent ? 'red' : 'blue'};" >
< pre style = "white-space: pre-wrap; font-family: Arial, sans-serif;" > ${analysis}< / pre >
< / div >
${isUrgent ? '< p style = "color: red; font-weight: bold;" > ⚠️ IMMEDIATE ATTENTION REQUIRED< / p > ' : ''}
< p > < em > Generated by Swarms Healthcare Monitoring Agent< / em > < / p >
`;
// Send email using Mailgun
const formData = new FormData();
formData.append('from', `Healthcare Monitor <alerts@${env.MAILGUN_DOMAIN}>` );
formData.append('to', env.MEDICAL_TEAM_EMAIL);
formData.append('subject', emailSubject);
formData.append('html', emailBody);
try {
### 1. **Dual Handler Pattern**
const response = await fetch(`https://api.mailgun.net/v3/${env.MAILGUN_DOMAIN}/messages`, {
- ** `fetch()` **: Handles HTTP requests, provides web UI for testing
method: 'POST',
- ** `scheduled()` **: Executes on cron schedule automatically
headers: {
- **Shared Logic** : Both use the same `handleStockAnalysis()` function
'Authorization': `Basic ${btoa(` api:${env.MAILGUN_API_KEY}`)}`
},
body: formData
});
if (response.ok) {
### 2. **Cron Configuration**
console.log('✅ Healthcare email alert sent successfully');
```jsonc
} else {
"triggers": {
console.error('❌ Failed to send healthcare email:', await response.text());
"crons": [
}
"0 */3 * * * " // Every 3 hours
} catch (error) {
"0 9 * * MON-FRI" // Weekdays at 9 AM
console.error('❌ Healthcare email error:', error);
]
}
}
}
```
function extractSeverity(analysis) {
### 3. **Real Data Integration**
if (analysis.includes('CRITICAL')) return 'critical';
- **Yahoo Finance API** : Free, no API key required
if (analysis.includes('URGENT')) return 'urgent';
- **Error Handling** : Timeout management, fallback responses
if (analysis.includes('WARNING')) return 'warning';
- **Parallel Processing** : Fetch multiple symbols simultaneously
return 'normal';
}
function getSeverityColor(severity) {
### 4. **Production Features**
switch(severity) {
- **Web Interface** : Test manually via browser
case 'critical': return 'red';
- **Structured Responses** : Consistent JSON format
case 'urgent': return 'orange';
- **Error Recovery** : Graceful failure handling
case 'warning': return 'yellow';
- **Logging** : Console output for debugging
default: return 'green';
}
}
```
## Deployment
## Deployment
```bash
```bash
# Deploy your cron job agents
# Deploy to Cloudflare
wrangler deploy
wrangler deploy
# Monitor logs
# View logs
wrangler tail
wrangler tail
# Test cron trigger manually
# Test cron manually
wrangler triggers cron "0 21 * * MON-FRI "
wrangler triggers cron "0 */3 * * * "
```
```
## Cost Optimization
- Use `gpt-4o-mini` for cost-effective analysis
- Set appropriate `max_tokens` limits
- Configure cron schedules to avoid unnecessary runs
- Implement error handling to prevent API waste
## Environment Variables
## Environment Variables
Add to `wrangler.toml` :
Add to `wrangler.jsonc` :
```toml
[env.production.vars]
SWARMS_API_KEY = "your-swarms-api-key"
# Stock API Keys (get free keys from these providers)
```jsonc
STOCK_API_KEY = "your-alpha-vantage-key" # Free: https://www.alphavantage.co/support/#api-key
{
FMP_API_KEY = "your-fmp-key" # Free: https://financialmodelingprep.com/developer/docs
"vars": {
"SWARMS_API_KEY": "your-swarms-api-key",
# Email Configuration (Mailgun)
"MAILGUN_API_KEY": "optional-for-emails",
MAILGUN_API_KEY = "your-mailgun-api-key" # Free: https://www.mailgun.com/
"MAILGUN_DOMAIN": "your-domain.com",
MAILGUN_DOMAIN = "your-domain .com"
"RECIPIENT_EMAIL": "alerts@company .com"
RECIPIENT_EMAIL = "investor@yourcompany.com"
}
MEDICAL_TEAM_EMAIL = "medical-team@hospital.com"
}
```
```
## API Endpoints Used
## Testing
1. **Deploy** : `wrangler deploy`
2. **Visit URL** : Open your worker URL to see the web interface
3. **Manual Test** : Click "Start Analysis" button
4. **Cron Test** : `wrangler triggers cron "0 */3 * * *"`
### Stock Data APIs
## Production Tips
- **Alpha Vantage** : Real-time stock prices, technical indicators (RSI, MACD)
- **Financial Modeling Prep** : Market news, earnings data, company fundamentals
- **Free Tier Limits** : Alpha Vantage (5 calls/min), FMP (250 calls/day)
### Real Market Data Flow
- **Error Handling** : Always wrap API calls in try-catch
1. **Fetch Live Data** : Current prices, volume, technical indicator s
- **Timeouts** : Use AbortController for external API calls
2. **Get Market News** : Recent earnings, economic events, analyst reports
- **Logging** : Use console.log for debugging in Cloudflare dashboard
3. **AI Analysis** : Swarms agents analyze real data for actionable insigh ts
- **Rate Limits** : Yahoo Finance is free but has rate limi ts
4. **Email Reports** : Professional HTML emails with analysis and data tables
- **Cost Control** : Set appropriate `max_tokens` in agent config
### Email Features
This minimal implementation provides a solid foundation for production AI agents on Cloudflare Workers with automated scheduling and real-time data integration.
- **Stock Reports** : Daily market analysis with data tables and key movers
- **Healthcare Alerts** : Color-coded severity levels with immediate attention flags
- **HTML Formatting** : Professional email templates with styling
- **Mailgun Integration** : Reliable email delivery service