DigitalOcean Functions Overview¶
Introduction¶
DigitalOcean Functions is a serverless computing platform that lets you run code without managing servers. Deploy functions that automatically scale, pay only for execution time, and integrate seamlessly with other DigitalOcean services.
Key Features¶
- Serverless: No infrastructure management
- Auto-Scaling: Scales automatically with demand
- Pay-per-Use: Billed per execution
- Multiple Languages: Node.js, Python, Go, PHP
- Event-Driven: Trigger from HTTP, schedules, events
- Fast Cold Starts: Optimized performance
- Built-in Monitoring: Logs and metrics included
- CI/CD Integration: Deploy from Git
- Environment Variables: Secure configuration
- Package Support: Use npm, pip, go modules
Functions Architecture¶
┌─────────────────────────────────────────────────────────────┐
│ Triggers │
│ ├─> HTTP Requests │
│ ├─> Scheduled (Cron) │
│ ├─> Webhooks │
│ └─> Events │
└────────────────────────────┬────────────────────────────────┘
│
┌────────▼────────┐
│ API Gateway │
│ (Routing) │
└────────┬────────┘
│
┌────────────────────┼────────────────────┐
│ │ │
┌────▼────┐ ┌────▼────┐ ┌────▼────┐
│Function │ │Function │ │Function │
│Instance │ │Instance │ │Instance │
│ #1 │ │ #2 │ │ #3 │
└────┬────┘ └────┬────┘ └────┬────┘
│ │ │
└────────────────────┼────────────────────┘
│
┌────────▼────────┐
│ Resources │
│ (DB, Storage) │
└─────────────────┘
Auto-scaling: 0 to 1000+ instances based on load
Supported Runtimes¶
Node.js¶
Versions:
├─> Node.js 18.x (LTS)
├─> Node.js 20.x (Latest)
└─> npm packages supported
Use Cases:
├─> API endpoints
├─> Webhooks
├─> Data processing
└─> Integrations
Python¶
Versions:
├─> Python 3.9
├─> Python 3.10
├─> Python 3.11
└─> pip packages supported
Use Cases:
├─> Data analysis
├─> ML inference
├─> Automation
└─> Scraping
Go¶
Versions:
├─> Go 1.19
├─> Go 1.20
├─> Go 1.21
└─> Go modules supported
Use Cases:
├─> High-performance APIs
├─> Concurrent processing
├─> System utilities
└─> Microservices
PHP¶
Versions:
├─> PHP 8.1
├─> PHP 8.2
└─> Composer packages supported
Use Cases:
├─> Web hooks
├─> Form processing
├─> Legacy integrations
└─> CMS extensions
Use Cases¶
1. API Endpoints¶
REST APIs:
├─> CRUD operations
├─> Data validation
├─> Authentication
└─> Rate limiting
Example:
├─> GET /api/users
├─> POST /api/users
├─> PUT /api/users/:id
└─> DELETE /api/users/:id
2. Webhooks¶
Event Handlers:
├─> GitHub webhooks
├─> Stripe payments
├─> Slack commands
└─> Custom integrations
Example:
├─> Process payment events
├─> Deploy on push
├─> Send notifications
└─> Update databases
3. Scheduled Tasks¶
Cron Jobs:
├─> Data backups
├─> Report generation
├─> Cleanup tasks
└─> Monitoring checks
Example:
├─> Daily database backup
├─> Hourly health checks
├─> Weekly reports
└─> Monthly cleanup
4. Data Processing¶
ETL Pipelines:
├─> Image processing
├─> File conversion
├─> Data transformation
└─> Batch processing
Example:
├─> Resize uploaded images
├─> Convert video formats
├─> Parse CSV files
└─> Generate thumbnails
5. Integrations¶
Third-Party Services:
├─> Payment processing
├─> Email sending
├─> SMS notifications
└─> Social media posting
Example:
├─> Stripe payment handler
├─> SendGrid email sender
├─> Twilio SMS sender
└─> Twitter bot
Pricing¶
Free Tier¶
Included:
├─> 90,000 GB-seconds/month
├─> 90,000 requests/month
└─> No credit card required
Equivalent to:
├─> ~25 hours of 1GB function
└─> ~90,000 quick requests
Paid Usage¶
Compute:
├─> $0.0000185 per GB-second
└─> Billed per 100ms
Requests:
├─> $0.30 per million requests
└─> First 90k free
Example Cost:
├─> 1M requests: $0.27
├─> 1M GB-seconds: $18.50
└─> Typical API: $5-20/month
Function Structure¶
Basic Function (Node.js)¶
// packages/hello/hello.js
function main(args) {
const name = args.name || 'World';
return {
body: {
message: `Hello, ${name}!`
}
};
}
exports.main = main;
With Dependencies¶
// packages/api/package.json
{
"name": "api",
"version": "1.0.0",
"dependencies": {
"axios": "^1.6.0"
}
}
// packages/api/api.js
const axios = require('axios');
async function main(args) {
const response = await axios.get('https://api.example.com/data');
return {
body: response.data
};
}
exports.main = main;
Python Function¶
# packages/process/process.py
import json
def main(args):
data = args.get('data', [])
processed = [item * 2 for item in data]
return {
'body': {
'result': processed
}
}
Go Function¶
// packages/handler/handler.go
package main
import (
"encoding/json"
)
type Response struct {
Body map[string]interface{} `json:"body"`
}
func Main(args map[string]interface{}) Response {
name := "World"
if n, ok := args["name"].(string); ok {
name = n
}
return Response{
Body: map[string]interface{}{
"message": "Hello, " + name + "!",
},
}
}
Project Configuration¶
project.yml¶
packages:
- name: api
functions:
- name: users
runtime: nodejs:18
web: true
environment:
DATABASE_URL: ${DATABASE_URL}
limits:
timeout: 30000
memory: 256
- name: process
runtime: python:3.11
web: false
schedule: '0 * * * *' # Hourly
limits:
timeout: 60000
memory: 512
Deployment¶
Using doctl¶
# Install doctl
brew install doctl
# Authenticate
doctl auth init
# Connect to Functions
doctl serverless connect
# Deploy
doctl serverless deploy .
# List functions
doctl serverless functions list
# Invoke function
doctl serverless functions invoke api/users
# View logs
doctl serverless activations logs --function api/users
Using GitHub Actions¶
# .github/workflows/deploy.yml
name: Deploy Functions
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Install doctl
uses: digitalocean/action-doctl@v2
with:
token: ${{ secrets.DIGITALOCEAN_TOKEN }}
- name: Deploy Functions
run: |
doctl serverless connect
doctl serverless deploy .
Best Practices¶
1. Performance¶
Optimization:
├─> Keep functions small and focused
├─> Minimize cold start time
├─> Use connection pooling
├─> Cache external data
└─> Optimize dependencies
Tips:
├─> Reuse connections
├─> Lazy load modules
├─> Use async/await
└─> Implement timeouts
2. Security¶
Best Practices:
├─> Use environment variables for secrets
├─> Validate input data
├─> Implement rate limiting
├─> Use HTTPS only
└─> Follow least privilege
Example:
├─> Store API keys in env vars
├─> Validate request parameters
├─> Limit request size
└─> Use authentication
3. Error Handling¶
async function main(args) {
try {
// Validate input
if (!args.email) {
return {
statusCode: 400,
body: { error: 'Email required' }
};
}
// Process request
const result = await processEmail(args.email);
return {
statusCode: 200,
body: { success: true, result }
};
} catch (error) {
console.error('Error:', error);
return {
statusCode: 500,
body: { error: 'Internal server error' }
};
}
}
4. Monitoring¶
Track Metrics:
├─> Execution time
├─> Error rate
├─> Invocation count
├─> Memory usage
└─> Cold starts
Tools:
├─> Built-in logs
├─> Activation history
├─> Custom metrics
└─> External monitoring
Common Patterns¶
REST API¶
// packages/api/users.js
const users = [];
function main(args) {
const method = args.__ow_method;
const path = args.__ow_path;
switch (method) {
case 'GET':
return { body: users };
case 'POST':
const user = JSON.parse(args.__ow_body);
users.push(user);
return { statusCode: 201, body: user };
case 'DELETE':
const id = path.split('/').pop();
const index = users.findIndex(u => u.id === id);
if (index > -1) {
users.splice(index, 1);
return { statusCode: 204 };
}
return { statusCode: 404 };
default:
return { statusCode: 405 };
}
}
Webhook Handler¶
// packages/webhooks/github.js
const crypto = require('crypto');
function verifySignature(payload, signature, secret) {
const hmac = crypto.createHmac('sha256', secret);
const digest = 'sha256=' + hmac.update(payload).digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(digest)
);
}
async function main(args) {
const signature = args.__ow_headers['x-hub-signature-256'];
const payload = args.__ow_body;
if (!verifySignature(payload, signature, process.env.GITHUB_SECRET)) {
return { statusCode: 401, body: { error: 'Invalid signature' } };
}
const event = JSON.parse(payload);
// Process webhook event
console.log('Received event:', event.action);
return { statusCode: 200, body: { success: true } };
}
Scheduled Task¶
# packages/tasks/backup.py
import os
from datetime import datetime
def main(args):
# Perform backup
timestamp = datetime.now().isoformat()
# Your backup logic here
print(f"Backup started at {timestamp}")
# Upload to Spaces
# ...
return {
'body': {
'success': True,
'timestamp': timestamp
}
}
Troubleshooting¶
Function Not Responding¶
# Check function status
doctl serverless functions list
# View recent activations
doctl serverless activations list --function api/users
# Get activation details
doctl serverless activations get ACTIVATION_ID
# View logs
doctl serverless activations logs --function api/users
Timeout Issues¶
# Increase timeout in project.yml
functions:
- name: slow-function
limits:
timeout: 60000 # 60 seconds
memory: 512 # More memory
Cold Start Optimization¶
// Initialize outside handler
const db = require('./db');
let connection;
async function main(args) {
// Reuse connection
if (!connection) {
connection = await db.connect();
}
// Use connection
const result = await connection.query('SELECT * FROM users');
return { body: result };
}
Documentation Structure¶
- Functions Overview - This page
- Creating Functions - Development guide
- Deploying Functions - Deployment methods
- Function Patterns - Common use cases