In the world of workflow automation, there's a silent killer of reliability: the partial state. Imagine a new user signs up. Your automation kicks off—it creates a user record in the database, but then fails while trying to send the welcome email because of a temporary API outage. Now what? You have a user who exists but was never welcomed, never onboarded, and is left in limbo. Your system is now in an inconsistent, "partial" state that requires manual cleanup and erodes user trust.
This is a common, frustrating problem that plagues brittle automations. The solution isn't more complex error-handling logic; it's a fundamental shift in how we design our automated tasks. The solution is to make them atomic.
At action.do, we believe that an atomic action is the fundamental building block of any robust automation. Let's explore why this "all-or-nothing" approach is critical for data integrity.
Most business processes aren't single events. A "user signup" process might involve:
If you code this as one large script, a failure at step 3 leaves the first two steps completed. The system is now in a state of data inconsistency. This partial success is often more dangerous than a complete failure because it can go undetected, causing cascading problems down the line.
The consequences are significant:
This is where the principle of atomicity comes in. In the context of action.do, an atomic action is the smallest, indivisible unit of work in a workflow. It represents a single, well-defined task that is guaranteed to either complete successfully or fail entirely, leaving no partial state behind.
Think of it like a bank transfer. Money is debited from one account and credited to another. It's unacceptable for the debit to succeed while the credit fails. The entire transaction must succeed or fail as a single, atomic unit. This is the level of reliability we should demand from our business automations.
By encapsulating each individual task into an atomic action, you create a powerful safety net. If an action to 'send an email' fails, the entire action fails cleanly. The parent workflow is immediately notified of this specific failure and can decide how to proceed—whether to retry, alert a human, or trigger a compensating action. There’s no ambiguity.
action.do is designed from the ground up around this powerful concept. We provide the framework to define any single, repeatable task as a powerful, API-callable atomic action.
Here’s how simple it is to define a robust, atomic action using TypeScript. This action encapsulates all the logic for sending a welcome email.
Let's break down why this is so effective:
Because each action.do is a self-contained, modular unit, it’s inherently reusable. You can define a single, reliable create-user-record action and call it from dozens of different agentic workflows—from a public sign-up form, an internal admin tool, or an API integration.
This promotes the "Don't Repeat Yourself" (DRY) principle for business-as-code. Instead of rewriting and debugging the same logic in multiple places, you build a library of trusted, atomic actions—the building blocks for all your automation needs. These actions then become the lego bricks that a workflow.do can orchestrate to build complex, scalable, and—most importantly—reliable business processes.
Stop letting partial states compromise your data and create manual work. By embracing atomicity, you can build automations that are predictable, reliable, and easy to debug.
With action.do, you're not just writing code; you're creating a robust foundation for all of your agentic workflows and task automation.
Ready to build with confidence? Explore action.do and start turning complex processes into simple, atomic, powerful actions.
import { action } from '@do-sdk/core';
export const sendWelcomeEmail = action({
name: 'send-welcome-email',
description: 'Sends a welcome email to a new user.',
inputs: {
to: { type: 'string', required: true },
name: { type: 'string', required: true }
},
handler: async ({ inputs, context }) => {
const { to, name } = inputs;
// Your email sending logic, including API calls, goes here.
// If any part of this logic throws an error, the entire
// action fails atomically.
console.log(`Sending welcome email to ${name} at ${to}`);
// On success, return a structured output.
return { success: true, messageId: 'xyz-123' };
},
});