When to Use
- Daily/weekly reports and analytics
- Scheduled email campaigns and notifications
- Data cleanup and maintenance tasks
- Background data processing and syncing
What They Do
- Run on fixed schedules (cron-like)
- Execute delayed tasks after events
- Process queued work items
- Maintain system health and data integrity
How Task Functions Work
- Schedule triggers at specified intervals (cron expressions or rate limits)
- Task function executes without user interaction
- Background work runs (emails, reports, cleanup, data processing)
- Task completes and returns execution summary
Task Function Examples
- Abandoned Cart Recovery
- Daily Sales Report
- Data Cleanup
- Weekly Newsletter
Send emails to users who left items in their cart:Schedule Trigger:
What Ollie Hub adds:
Cron Expression
cron(*/30 * * * *) - Every 30 minutes
[
{
"id": "cart_123",
"userId": "user_456",
"items": [
{"productId": "prod_789", "quantity": 1, "price": 199.99}
],
"total": 199.99,
"lastUpdated": "2024-01-12T08:15:30Z"
}
]
export const handler = async (event) => {
try {
// Find abandoned carts (inactive for 2+ hours)
const cutoffTime = new Date(Date.now() - 2 * 60 * 60 * 1000);
const abandonedCarts = await findAbandonedCarts(cutoffTime);
console.log(`Found ${abandonedCarts.length} abandoned carts to process`);
const results = {
processed: 0,
emailsSent: 0,
errors: 0,
skipped: 0
};
for (const cart of abandonedCarts) {
try {
// Check if we've already sent recovery email for this cart
const emailSent = await hasRecoveryEmailBeenSent(cart.id);
if (emailSent) {
results.skipped++;
continue;
}
// Get user and personalize recovery email
const user = await getUserProfile(cart.userId);
const emailData = {
userEmail: user.email,
userName: user.firstName,
cartItems: cart.items,
cartTotal: cart.total,
recoveryLink: `https://mystore.com/cart/recover?token=${cart.recoveryToken}`
};
// Send personalized recovery email
await sendAbandonedCartEmail(emailData);
// Mark cart as having recovery email sent
await markRecoveryEmailSent(cart.id);
// Log analytics event
await logAnalytics('abandoned_cart_recovery_sent', {
cartId: cart.id,
userId: cart.userId,
cartValue: cart.total,
itemCount: cart.items.length
});
results.emailsSent++;
results.processed++;
} catch (error) {
console.error(`Failed to process cart ${cart.id}:`, error);
results.errors++;
}
}
return {
statusCode: 200,
body: JSON.stringify({
message: 'Abandoned cart recovery task completed',
timestamp: new Date().toISOString(),
summary: results
})
};
} catch (error) {
console.error('Abandoned cart recovery task failed:', error);
return {
statusCode: 500,
body: JSON.stringify({
error: 'Task execution failed',
message: error.message
})
};
}
};
{
"message": "Task completed",
"processed": 25
}
π See Hub Enhancements
π See Hub Enhancements
Enhanced Response
{
"message": "Abandoned cart recovery task completed",
"timestamp": "2024-01-12T10:30:45.123Z",
"summary": {
"processed": 25,
"emailsSent": 18,
"errors": 2,
"skipped": 5
},
"details": {
"discoveredCarts": 25,
"eligibleForRecovery": 23,
"duplicatesPrevented": 5,
"totalCartValue": 4750.00,
"averageCartValue": 190.00,
"topCategories": ["electronics", "clothing", "home"],
"emailTemplatesUsed": {
"first_reminder": 12,
"second_reminder": 4,
"final_discount": 2
}
},
"performance": {
"executionTime": "2.3s",
"cartsPerSecond": 10.9,
"emailDeliveryTime": "1.2s"
},
"nextRun": "2024-01-12T11:00:00.000Z"
}
- β Intelligent cart discovery with time-based filtering
- β Personalized email content with user data
- β Duplicate email prevention system
- β Revenue impact tracking and analytics
- β Performance metrics and optimization data
- β Detailed error handling and reporting
- β Multi-stage recovery email campaigns
Generate and email daily sales reports:Schedule Trigger:
What Ollie Hub adds:
Cron Expression
cron(0 8 * * *) - Daily at 8:00 AM
{
"date": "2024-01-11",
"orders": [
{
"id": "ord_123",
"total": 299.99,
"isNewCustomer": true,
"timestamp": "2024-01-11T14:30:00Z"
}
],
"totalRevenue": 15420.75,
"totalOrders": 47
}
export const handler = async (event) => {
try {
const today = new Date();
const yesterday = new Date(today);
yesterday.setDate(yesterday.getDate() - 1);
// Generate comprehensive sales report
const salesData = await generateSalesReport(yesterday);
// Calculate key metrics
const metrics = {
totalRevenue: salesData.orders.reduce((sum, order) => sum + order.total, 0),
totalOrders: salesData.orders.length,
averageOrderValue: salesData.orders.length > 0
? salesData.totalRevenue / salesData.orders.length
: 0,
newCustomers: salesData.orders.filter(o => o.isNewCustomer).length,
returningCustomers: salesData.orders.filter(o => !o.isNewCustomer).length
};
// Generate report content
const reportData = {
date: yesterday.toISOString().split('T')[0],
metrics,
topProducts: await getTopProducts(yesterday),
customerInsights: await getCustomerInsights(yesterday),
comparisonWithPreviousDay: await getComparison(yesterday)
};
// Create HTML email report
const emailHTML = await generateReportHTML(reportData);
// Send to management team
const recipients = await getReportRecipients('daily-sales');
await sendEmail({
to: recipients,
subject: `Daily Sales Report - ${reportData.date}`,
html: emailHTML,
attachments: [
{
filename: `sales-report-${reportData.date}.pdf`,
content: await generateReportPDF(reportData)
}
]
});
// Store report in database for historical tracking
await storeDailySalesReport(reportData);
return {
statusCode: 200,
body: JSON.stringify({
message: 'Daily sales report generated and sent',
date: reportData.date,
metrics
})
};
} catch (error) {
console.error('Daily sales report failed:', error);
// Send error notification to admin
await sendErrorNotification('daily-sales-report', error);
return {
statusCode: 500,
body: JSON.stringify({
error: 'Report generation failed'
})
};
}
};
{
"message": "Report sent",
"recipients": 3
}
π See Hub Enhancements
π See Hub Enhancements
Enhanced Response
{
"message": "Daily sales report generated and sent",
"date": "2024-01-11",
"metrics": {
"totalRevenue": 15420.75,
"totalOrders": 47,
"averageOrderValue": 328.10,
"newCustomers": 12,
"returningCustomers": 35
},
"reportDetails": {
"reportId": "sales-2024-01-11",
"recipients": 3,
"emailsSent": 3,
"attachmentSize": "2.4MB",
"generationTime": "4.2s"
},
"insights": {
"topSellingProduct": "MacBook Pro 14-inch",
"peakSalesHour": "14:00-15:00",
"customerRetentionRate": "74.5%",
"dayOverDayGrowth": "+12.3%"
},
"nextReportDue": "2024-01-13T08:00:00.000Z"
}
- β Comprehensive revenue and customer metrics
- β Top-performing products analysis
- β Customer acquisition and retention insights
- β Day-over-day growth comparisons
- β PDF attachment with charts and graphs
- β Historical data storage and trends
- β Executive dashboard integration
Clean up expired sessions and temporary data:Schedule Trigger:
What Ollie Hub adds:
Cron Expression
cron(0 */6 * * *) - Every 6 hours
{
"expiredSessions": {
"cutoffHours": 24,
"estimatedCount": 1200
},
"temporaryFiles": {
"cutoffHours": 1,
"estimatedSizeMB": 450
},
"oldLogs": {
"cutoffDays": 30,
"estimatedCount": 50000
}
}
export const handler = async (event) => {
try {
const results = {
expiredSessions: 0,
temporaryFiles: 0,
oldLogs: 0,
failedUploads: 0,
totalSpaceFreed: 0
};
// Clean expired user sessions (older than 24 hours)
const expiredSessions = await cleanupExpiredSessions(24);
results.expiredSessions = expiredSessions.count;
// Remove temporary files (older than 1 hour)
const tempFiles = await cleanupTemporaryFiles(1);
results.temporaryFiles = tempFiles.count;
results.totalSpaceFreed += tempFiles.spaceFreed;
// Archive old application logs (older than 30 days)
const oldLogs = await archiveOldLogs(30);
results.oldLogs = oldLogs.count;
results.totalSpaceFreed += oldLogs.spaceFreed;
// Clean up failed upload attempts (older than 1 day)
const failedUploads = await cleanupFailedUploads(1);
results.failedUploads = failedUploads.count;
results.totalSpaceFreed += failedUploads.spaceFreed;
// Update system health metrics
await updateSystemHealthMetrics({
lastCleanup: new Date().toISOString(),
itemsProcessed: Object.values(results).reduce((sum, val) =>
typeof val === 'number' ? sum + val : sum, 0),
spaceFreedMB: Math.round(results.totalSpaceFreed / 1024 / 1024)
});
return {
statusCode: 200,
body: JSON.stringify({
message: 'Data cleanup completed successfully',
timestamp: new Date().toISOString(),
results
})
};
} catch (error) {
console.error('Data cleanup failed:', error);
return {
statusCode: 500,
body: JSON.stringify({
error: 'Cleanup task failed'
})
};
}
};
{
"message": "Cleanup completed",
"itemsProcessed": 1250
}
π See Hub Enhancements
π See Hub Enhancements
Enhanced Response
{
"message": "Data cleanup completed successfully",
"timestamp": "2024-01-12T10:30:45.123Z",
"results": {
"expiredSessions": 1200,
"temporaryFiles": 450,
"oldLogs": 50000,
"failedUploads": 75,
"totalSpaceFreed": 524288000
},
"summary": {
"totalItemsProcessed": 51725,
"spaceFreedMB": 500,
"executionTime": "45.2s",
"performanceGain": "15% faster DB queries"
},
"systemHealth": {
"diskUsageAfterCleanup": "68%",
"sessionTableSize": "12.3MB",
"cacheHitRateImprovement": "+5.2%",
"nextCleanupDue": "2024-01-12T16:00:00.000Z"
}
}
- β Intelligent expired session detection and removal
- β Temporary file cleanup with size optimization
- β Log archival and rotation management
- β Failed upload cleanup and recovery
- β Storage space optimization tracking
- β System health metrics and performance impact
- β Database query performance improvements
Send personalized weekly newsletters to subscribers:Schedule Trigger:
What Ollie Hub adds:
Cron Expression
cron(0 9 * * MON) - Every Monday at 9:00 AM
[
{
"id": "sub_123",
"email": "john@example.com",
"preferences": {
"categories": ["tech", "business"],
"frequency": "weekly"
},
"unsubscribeToken": "tok_abc123"
}
]
export const handler = async (event) => {
try {
// Get all active newsletter subscribers
const subscribers = await getNewsletterSubscribers();
console.log(`Processing newsletter for ${subscribers.length} subscribers`);
const results = {
emailsSent: 0,
errors: 0,
unsubscribes: 0,
bounces: 0
};
// Get content for the week
const weeklyContent = await generateWeeklyContent();
// Process subscribers in batches to avoid overwhelming the email service
const batchSize = 100;
for (let i = 0; i < subscribers.length; i += batchSize) {
const batch = subscribers.slice(i, i + batchSize);
const batchPromises = batch.map(async (subscriber) => {
try {
// Personalize content for this subscriber
const personalizedContent = await personalizeNewsletter(
weeklyContent,
subscriber
);
// Send personalized email
await sendEmail({
to: subscriber.email,
subject: `Your Weekly Update - Week of ${weeklyContent.weekOf}`,
html: personalizedContent.html,
text: personalizedContent.text,
unsubscribeLink: `https://myapp.com/unsubscribe?token=${subscriber.unsubscribeToken}`
});
// Track successful send
await trackNewsletterSent(subscriber.id, weeklyContent.id);
results.emailsSent++;
} catch (error) {
console.error(`Failed to send newsletter to ${subscriber.email}:`, error);
results.errors++;
}
});
// Wait for batch to complete before processing next batch
await Promise.all(batchPromises);
// Brief pause between batches
await new Promise(resolve => setTimeout(resolve, 1000));
}
// Update newsletter campaign stats
await updateCampaignStats(weeklyContent.id, results);
return {
statusCode: 200,
body: JSON.stringify({
message: 'Weekly newsletter campaign completed',
campaignId: weeklyContent.id,
results
})
};
} catch (error) {
console.error('Newsletter campaign failed:', error);
return {
statusCode: 500,
body: JSON.stringify({
error: 'Newsletter campaign failed'
})
};
}
};
{
"message": "Newsletter sent",
"emailsSent": 5420
}
π See Hub Enhancements
π See Hub Enhancements
Enhanced Response
{
"message": "Weekly newsletter campaign completed",
"campaignId": "newsletter-2024-w02",
"weekOf": "2024-01-08",
"results": {
"emailsSent": 5420,
"errors": 12,
"unsubscribes": 3,
"bounces": 8
},
"performance": {
"totalSubscribers": 5435,
"successRate": "99.7%",
"deliveryTime": "12.4 minutes",
"batchesProcessed": 55
},
"engagement": {
"expectedOpenRate": "24.5%",
"expectedClickRate": "4.2%",
"topContent": "Weekly Tech Roundup",
"personalizationScore": "High"
},
"nextCampaign": "2024-01-15T09:00:00.000Z"
}
- β Batch processing for scalability and deliverability
- β Personalized content based on subscriber preferences
- β Unsubscribe link management and tracking
- β Campaign performance metrics and analytics
- β Error handling with detailed reporting
- β Rate limiting to prevent spam flags
- β Engagement prediction and optimization
Best Practices
Keep Tasks Idempotent
Design tasks to handle being run multiple times safely. Check for existing work before processing.
Process in Batches
For large datasets, process items in small batches to avoid timeouts and memory issues.
Monitor and Alert
Set up monitoring for task failures and send notifications when critical tasks fail.
Handle Failures Gracefully
Implement retry logic with exponential backoff. Store failed items for manual review.
Next Steps
Best Practices
Task patterns, error handling, and scheduling tips
Request Functions
Learn to handle user requests and API calls
Response Functions
Customize responses with analytics and enhancements
Pro Tip: Task functions can trigger Request functions to process data, and Response functions can enhance the results. They work great together! Check out our Best Practices guide for implementation patterns.