In modern software development, automation is no longer a luxury; it's the engine of efficiency and scale. Yet, we've all felt the pain of brittle automation scripts—monolithic processes where a single, minor failure can bring the entire system to a halt. A temporary network blip or a third-party API timeout shouldn't require manual intervention or cause a cascade of errors.
The solution isn't to build bigger, more complex scripts. It's to think smaller.
Enter the concept of the atomic action, the fundamental building block of resilient automation on the .do platform. An action.do represents a single, executable unit of work. By themselves, they are precise and reliable. When chained together, they become the foundation for orchestrating even the most complex workflows with unparalleled robustness.
Before you can build a skyscraper, you need to trust your bricks. On the .do platform, the atomic action is that brick.
As defined in our FAQs, an atomic action is the smallest, indivisible unit of work. Think of it not as a simple function call, but as a function elevated to a fully managed microservice.
Each action is designed to do one thing and do it exceptionally well. When you execute an action.do, you're not just running code; you're invoking a service that is logged, monitored, secured, and independently scalable. This "Business-as-Code" approach guarantees that each step in your process is testable, reusable, and resilient.
The provided action.do example shows this simplicity in action:
import { Do } from '@do-sdk/core';
// Initialize the .do client
const doClient = new Do({ apiKey: 'YOUR_API_KEY' });
// Execute a single, atomic action for sending an email
async function sendWelcomeEmail(to: string, name: string) {
try {
const result = await doClient.action('email.send').run({
to,
subject: `Welcome, ${name}!`,
body: `We're thrilled to have you join us.`
});
console.log('Action Succeeded:', result.id);
} catch (error) {
console.error('Action Failed:', error);
}
}
This is powerful for a single task. But its true potential is unlocked when you start chaining these actions together.
Let's move beyond a single email. Consider a common business process: new user onboarding. A typical workflow might involve several distinct steps:
Attempting to code this in a single, monolithic function creates tight coupling and fragility. If the Slack API is down, should the entire user creation fail?
With atomic actions, you compose this process by chaining independent services.
Here’s how you can orchestrate the user onboarding workflow by chaining action.do calls. Each await ensures that one step completes successfully before the next begins.
import { Do } from '@do-sdk/core';
// Initialize the .do client with your API key
const doClient = new Do({ apiKey: 'YOUR_API_KEY' });
// A multi-action workflow for onboarding a new user
async function onboardNewUser(user: { email: string; name: string }) {
try {
console.log(`Starting onboarding for ${user.email}...`);
// Step 1: Create user in the database (Atomic Action)
const newUser = await doClient.action('database.users.create').run({
email: user.email,
name: user.name,
createdAt: new Date().toISOString()
});
console.log(`✅ Step 1 Succeeded: User created with ID ${newUser.id}`);
// Step 2: Send a welcome email (Atomic Action)
await doClient.action('email.send').run({
to: user.email,
templateId: 'welcome-template',
templateData: { name: user.name }
});
console.log(`✅ Step 2 Succeeded: Welcome email sent to ${user.email}`);
// Step 3: Notify internal team via Slack (Atomic Action)
await doClient.action('slack.channel.post').run({
channel: '#signups',
text: `🎉 New user joined: ${user.name} (${user.email})`
});
console.log(`✅ Step 3 Succeeded: Slack notification sent.`);
console.log('Onboarding workflow completed successfully!');
return { status: 'success', userId: newUser.id };
} catch (error) {
console.error('🔥 Onboarding Workflow Failed:', error);
// The .do platform allows triggering compensatory actions here,
// e.g., cleaning up created records or adding the user to a retry queue.
}
}
// Trigger the workflow for a new user
onboardNewUser({ email: 'new.user@example.com', name: 'Alex' });
Chaining atomic actions isn't just a cleaner way to write code; it fundamentally changes the reliability and scalability of your automations.
What happens if Step 3 (sending a Slack message) fails? In a traditional script, this might be an unhandled exception. With action.do, the failure is isolated. The user has already been created and has received their welcome email. The .do platform logs the specific failure of the slack.channel.post action. You can configure automatic retry policies (e.g., "try again 3 times with exponential backoff") or trigger a compensatory action, ensuring the workflow can gracefully handle transient failures without manual intervention.
Because each action.do is a managed service, the platform handles scaling for you. If a marketing campaign brings in 10,000 new users in an hour, the database.users.create and email.send services can scale independently to handle the load, without you needing to provision a single server.
The slack.channel.post action you used for onboarding can be reused in dozens of other workflows—from critical system alerts to daily sales reports. By defining your unique business logic as custom actions, you build a standardized palette of reusable components for your entire organization.
Simple chains are just the beginning. The true power of the .do platform lies in building dynamic, agentic workflows. By introducing conditional logic, parallel execution, and even AI-driven decision-making actions, you can create automations that don't just follow a script but can react, adapt, and make choices based on real-time data.
It all starts with a single, atomic action. By mastering the art of chaining these fundamental building blocks, you move from writing fragile scripts to orchestrating robust, scalable, and intelligent business processes.
Ready to build automations that don't break? Start composing your workflows with action.do on the .do platform today.