Compute Functions¶
Overview¶
Compute Functions are serverless functions that run within Centrali's secure sandbox environment. They can be triggered by events, scheduled to run at specific times, or invoked on-demand.
What are Compute Functions?¶
Compute functions allow you to: - Process data: Transform, validate, or enrich records - Automate workflows: React to data changes automatically - Integrate systems: Call external APIs and services - Run scheduled tasks: Periodic data cleanup, reports, backups - Implement business logic: Custom calculations and validations
Key Features¶
Secure Sandbox¶
- Functions run in isolated environments
- No access to file system or network (except approved APIs)
- CPU and memory limits enforced
- Automatic timeout after 5 minutes
Built-in APIs¶
Functions have access to: - Data API: Query and modify records in your workspace - Storage API: Upload and download files - HTTP Client: Make external API calls - Crypto API: SHA256 hashing and HMAC-SHA256 signing - Base64 API: Encode and decode Base64 strings (useful for Basic Auth headers) - Logging: api.log() for general logging, api.logError() for error logging with context
Event-Driven¶
Functions can be triggered by: - Record events: Created, updated, deleted, restored, reverted - Schedule: Interval-based, cron expression, or one-time execution - Manual: On-demand invocation via API - HTTP Triggers: External HTTP requests
See Also: Event Payloads Reference for detailed documentation on event payload structures.
Creating a Function¶
Step 1: Create the Function¶
Functions are created in a single step with inline code:
curl -X POST https://api.centrali.io/workspace/my-workspace/api/v1/compute-functions \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "process-order",
"description": "Process new orders and send notifications",
"code": "async function run() {\n const recordId = executionParams.recordId;\n \n // Query the order record\n const order = await api.fetchRecord(recordId);\n \n // Call external API\n await api.httpPost(\"https://api.example.com/notify\", {\n orderId: order.id,\n total: order.data.total\n }, {\n headers: { \"Authorization\": \"Bearer \" + triggerParams.apiKey }\n });\n \n return { success: true };\n}"
}'
Response:
{
"id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
"name": "process-order",
"description": "Process new orders and send notifications",
"code": "async function run() { ... }",
"workspaceSlug": "my-workspace",
"createdBy": "user-uuid",
"createdAt": "2025-01-15T10:30:00.000Z",
"updatedAt": "2025-01-15T10:30:00.000Z"
}
Step 2: Test the Function¶
Test function code before attaching triggers:
curl -X POST https://api.centrali.io/workspace/my-workspace/api/v1/compute-functions/test \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"code": "async function run() {\n const recordId = executionParams.recordId;\n const order = await api.fetchRecord(recordId);\n return { success: true, orderId: order.id };\n}",
"params": {
"recordId": "550e8400-e29b-41d4-a716-446655440000"
}
}'
Step 3: Publish from Draft (Optional)¶
If you use the draft workflow, publish a draft to create the function:
curl -X POST https://api.centrali.io/workspace/my-workspace/api/v1/compute-functions/DRAFT_ID/publish \
-H "Authorization: Bearer YOUR_TOKEN"
Function Code Structure¶
Basic Structure¶
All compute functions must define a run() function:
Important: The function must be named run, not handler or anything else.
Available Globals¶
Functions have access to these global objects:
| Global | Purpose |
|---|---|
api | Data operations, HTTP, utilities |
triggerParams | Static config from trigger setup (API keys, endpoints) |
executionParams | Runtime data passed when invoking the function |
Date, Math | Standard JavaScript globals |
setTimeout, setInterval | Timer functions |
The api Object¶
// Record Operations
api.queryRecords(structureSlug, options)
api.fetchRecord(recordId)
api.fetchRecordByUniqueField(structureSlug, field, value)
api.createRecord(structureSlug, data)
api.updateRecord(recordId, data)
api.deleteRecord(recordId, hardDelete)
api.incrementField(recordId, field, amount)
api.decrementField(recordId, field, amount)
api.aggregateRecords(structureSlug, options)
// HTTP Client (domain allowlist required)
// Returns { status, statusText, headers, data }
api.httpGet(url, options)
api.httpPost(url, data, options)
api.httpPut(url, data, options)
api.httpDelete(url, options)
// Utilities
api.log(message) // Logging (string or object)
api.uuid() // Generate UUID
api.formatDate(date, format)
api.renderTemplate(template, data, options) // Handlebars templates
// Libraries
api.lodash // Subset of lodash functions
api.math // Math.js for calculations
Parameters¶
triggerParams - Static configuration set when creating the trigger:
// Configured in trigger setup
const apiKey = triggerParams.apiKey;
const endpoint = triggerParams.endpoint;
executionParams - Runtime data passed when invoking:
// For on-demand triggers: the payload from SDK/API call
// For event-driven triggers: the event payload (recordId, data, etc.)
const orderId = executionParams.orderId;
const action = executionParams.action;
Event-Driven Trigger Payload¶
For event-driven triggers, executionParams contains:
{
event: "record_created", // or record_updated, record_deleted, etc.
workspaceSlug: "my-workspace",
recordSlug: "orders",
recordId: "uuid-here",
data: { /* record data or { before, after } for updates */ },
timestamp: "2025-01-15T10:00:00Z"
}
Function Examples¶
Example 1: Send Welcome Email¶
async function run() {
// For event-driven triggers, executionParams contains the event
const { recordId, data } = executionParams;
// Send welcome email via external service
await api.httpPost('https://api.sendgrid.com/v3/mail/send', {
to: data.email,
subject: 'Welcome!',
text: `Hello ${data.name}, welcome to our platform!`
}, {
headers: {
'Authorization': `Bearer ${triggerParams.SENDGRID_API_KEY}`
}
});
api.log({ message: 'Welcome email sent', userId: recordId });
return { success: true };
}
Example 2: Calculate Order Total¶
async function run() {
const orderId = executionParams.recordId;
// Get order record
const order = await api.fetchRecord(orderId);
// Query line items
const lineItems = await api.queryRecords('order-items', {
filter: { 'data.orderId': orderId }
});
// Calculate total
let total = 0;
for (const item of lineItems.data) {
total += item.data.price * item.data.quantity;
}
// Update order with calculated total
await api.updateRecord(orderId, { total });
return { success: true, total };
}
Example 3: Scheduled Cleanup¶
async function run() {
// Delete records older than 30 days
const thirtyDaysAgo = new Date();
thirtyDaysAgo.setDate(thirtyDaysAgo.getDate() - 30);
const oldRecords = await api.queryRecords('logs', {
dateWindow: {
field: 'createdAt',
to: thirtyDaysAgo.toISOString()
},
pageSize: 100
});
let deleted = 0;
for (const record of oldRecords.data) {
await api.deleteRecord(record.id, true);
deleted++;
}
api.log({ message: 'Cleanup complete', deleted });
return { success: true, deleted };
}
Function Parameters¶
Static parameters are configured through trigger metadata (triggerMetadata.params) when creating or updating a trigger. They are available in your function code via the triggerParams global.
Configuring Parameters¶
Parameters are set in the trigger's triggerMetadata.params field:
curl -X POST https://api.centrali.io/workspace/my-workspace/api/v1/function-triggers \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "order-processor",
"functionId": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
"executionType": "on-demand",
"triggerMetadata": {
"params": {
"WEBHOOK_URL": "https://api.example.com/webhook",
"API_KEY": {
"value": "sk_live_abc123",
"encrypt": true
}
}
}
}'
Sensitive values can be encrypted at rest by using { "value": "...", "encrypt": true }. Encrypted parameters are automatically decrypted before function execution.
Accessing Parameters¶
Parameters are available in the triggerParams global:
async function run() {
const apiKey = triggerParams.API_KEY;
const webhookUrl = triggerParams.WEBHOOK_URL;
// Use parameters in your code
await api.httpPost(webhookUrl, { data: 'example' }, {
headers: { 'Authorization': `Bearer ${apiKey}` }
});
return { success: true };
}
See the Function Triggers API for full documentation on parameter encryption.
Triggers¶
Triggers define when your function executes. Centrali supports four trigger types: event-driven (on record changes), scheduled (cron, interval, or one-time), on-demand (manual API/SDK invocation), and HTTP (external webhook URL).
For a complete guide on choosing and configuring triggers, see Triggers.
For the raw API endpoints, see the Function Triggers API Reference.
Monitoring & Debugging¶
View All Function Runs¶
curl -X GET https://api.centrali.io/workspace/my-workspace/api/v1/function-runs \
-H "Authorization: Bearer YOUR_TOKEN"
View Runs for a Specific Function¶
curl -X GET https://api.centrali.io/workspace/my-workspace/api/v1/function-runs/function/f47ac10b-58cc-4372-a567-0e02b2c3d479 \
-H "Authorization: Bearer YOUR_TOKEN"
View a Specific Run¶
curl -X GET https://api.centrali.io/workspace/my-workspace/api/v1/function-runs/RUN_ID \
-H "Authorization: Bearer YOUR_TOKEN"
Re-run Functions¶
You can re-run any previous function execution to retry or debug. Re-run is supported for all trigger types (on-demand, event-driven, scheduled, and HTTP).
See Function Re-run documentation.
Best Practices¶
Code Organization¶
- Keep functions focused on a single task
- Extract reusable logic to helper functions
- Use clear variable and function names
- Add comments for complex logic
Error Handling¶
async function run() {
try {
// Your code here
return { success: true };
} catch (error) {
// Log the error with context
api.log({
level: 'error',
message: error.message,
stack: error.stack
});
// Return error response (don't throw - return success: false)
return { success: false, error: error.message };
}
}
Performance¶
- Minimize external API calls
- Cache frequently accessed data
- Use bulk operations for multiple records
- Set appropriate timeout limits
Security¶
- Store secrets as encrypted parameters
- Validate input data
- Use HTTPS for external calls
- Follow principle of least privilege
Limits & Quotas¶
Default limits: - Execution time: 5 minutes maximum - Memory: 512 MB - Concurrent runs: 10 per function - Code size: 10 MB - External HTTP calls: 100 per execution
Related Documentation¶
- Event Payloads Reference - Detailed event payload documentation
- Compute Functions API - Complete API reference
- Function Triggers API - Trigger configuration
- Function Code Guide - Detailed coding guide
- Re-run Feature - Re-running failed functions