CertNote/ Commute Study Notes
Roadmap
KOEN
CLF-C02 · FoundationalCloud Practitioner - Foundational
DVA-C02 · AssociateDeveloper - Associate
  • Week 1
    • 1.AWS from a Developer's Perspective: Regions, Infrastructure, and the Boundary of Responsibility
    • 2.The 4 Core Entities of IAM: User, Group, Role, Policy
    • 3.STS and Policy Conditions: The Deep World of Temporary Credentials
    • 4.AWS CLI and SDK: From Credential Chaining to SigV4
    • 5.Week 1 Review: The Chain of Trust Built by Infrastructure and IAM
  • Week 2
  • Week 3
  • Week 4
  • Week 5
  • Week 6
  • Week 7
  • Week 8
  • Week 9
  • Week 10
  • Week 11
    • 1.SQS: How a Single Queue Decouples a System
    • 2.SNS: Publish Once and Everyone Hears It
    • 3.Kinesis: A Log That Holds On to Flowing Data
    • 4.Step Functions and AppSync: Taking the Flow Out of the Code
    • 5.Week 11 Review: The Questions That Divide the Messaging Models
  • Week 12
  • Week 13
SAA-C03 · AssociateSolutions Architect - Associate
SOA-C02 · AssociateCloudOps Engineer - Associate
SAP-C02 · ProfessionalSolutions Architect - Professional
DOP-C02 · ProfessionalDevOps Engineer - Professional
Linux Master 2 · 2급KAIT Linux Master - Level 2
SCS-C03 · SpecialtySecurity - Specialty
Linux Master 1 · 1급KAIT Linux Master - Level 1
MLA-C01 · AssociateMachine Learning Engineer - Associate
AIF-C01 · FoundationalAI Practitioner - Foundational
DEA-C01 · AssociateData Engineer - Associate
MLS-C01 · SpecialtyMachine Learning - Specialty
SQLD · 개발자SQL Developer (SQLD)

© CertNote · 주간랩스

  • About
  • Changelog
  • Contact
  • Terms
  • Privacy
← DVA-C02/Week 11/Day 4

Based on the DVA-C02 exam guide·Report an error

DVA-C02· AssociateWeek 11 · Day 4~34 min read

Day 4 - Step Functions and AppSync: Taking the Flow Out of the Code

SQS, SNS, and Kinesis, which we've covered so far, were tools for separating components. But real business processes require weaving back together in order the pieces you've separated. "Validate the order → check inventory → process payment → refund if it fails → send a notification if it succeeds." If you write this into a Lambda with if-else and try-catch, that function soon becomes bloated, and the state hides deep in the code so you can't tell "which step it stopped at right now." AWS Step Functions takes this flow (workflow) out of the code and turns it into an explicit state machine. AppSync applies a similar spirit to the data layer, letting you declare the "flow" of gathering data from multiple backends in a single GraphQL query.

In DVA-C02, Step Functions tends to show up in forms like "how do you orchestrate Lambda," "the difference between Standard and Express," and "how do you wait for a response from an external system." AppSync is tested as "real-time subscriptions," "multiple data sources," and "the difference from API Gateway." This article covers why separating the workflow from the code is valuable, the theoretical foundation of state machines, the problems solved by service integration patterns (.sync, .waitForTaskToken), and where GraphQL is fundamentally different from REST.

Why Take the Workflow Out of the Code: Orchestration vs. Choreography

Consider a case where 5 Lambda functions must run in order. The simplest approach is a chain, where function A invokes function B directly when it finishes, and B invokes C. This is called choreography. Without a central conductor, each one knows what comes next. This approach falls apart quickly. If an error occurs at C, how do you roll back A and B? Which step is the workflow at now? What if you want to retry B? This logic is scattered across the functions and the code becomes tangled.

Orchestration is the opposite. A central conductor (Step Functions) knows the whole flow, calls each step, and manages errors, retries, branching, and parallelism. Each Lambda does only its own job and doesn't know "what to do next." The flow logic is gathered in one place not as code but as a declarative definition (Amazon States Language, JSON), so it is visualized and leaves an execution history.

{
  "StartAt": "ValidateOrder",
  "States": {
    "ValidateOrder": {
      "Type": "Task",
      "Resource": "arn:aws:lambda:...:ValidateOrder",
      "Next": "CheckInventory",
      "Catch": [{"ErrorEquals": ["ValidationError"], "Next": "OrderFailed"}]
    },
    "CheckInventory": {
      "Type": "Choice",
      "Choices": [{"Variable": "$.inStock", "BooleanEquals": false, "Next": "Refund"}],
      "Default": "ProcessPayment"
    },
    "ProcessPayment": {
      "Type": "Task",
      "Resource": "arn:aws:lambda:...:ProcessPayment",
      "Retry": [{"ErrorEquals": ["Lambda.ServiceException"],
                 "IntervalSeconds": 2, "MaxAttempts": 3, "BackoffRate": 2.0}],
      "Next": "OrderSuccess"
    },
    "OrderSuccess": {"Type": "Succeed"},
    "OrderFailed": {"Type": "Fail", "Error": "OrderError"},
    "Refund": {"Type": "Task", "Resource": "arn:aws:lambda:...:Refund", "Next": "OrderFailed"}
  }
}

What Step Functions implements is the fundamental computer science concept of a Finite State Machine (FSM). It is a model in which a system is in one of a finite set of states, and transitions between states occur according to input. FSMs have been the foundation of automata theory since the 1950s (Mealy and Moore machines), and regular expression engines, network protocols, and UI state management are all FSMs. Step Functions applies this abstraction to distributed workflows, where each "State" expresses a task, branch, parallel run, or wait, and transitions are declared with Next. When you model a flow as an FSM, you can visually catch defects such as "unreachable states," "missing transitions," and "infinite loops." These are things you couldn't see when they were buried in code.

Orchestration vs. choreography is a long-standing debate in microservice design.

  • Choreography (event-driven, each reacts on its own) is loosely coupled and scales naturally, but the overall flow is not stated explicitly anywhere, so it's hard to trace "what's happening right now" (emergent behavior).
  • Orchestration (central control) states the flow explicitly in one place, making visibility, debugging, and error handling easy, but the conductor becomes a coupling point.
  • In practice, the two are mixed. The big flow between services is loosely coupled with events (EventBridge/SNS), while the steps within a single business transaction are written explicitly with Step Functions.
  • If you need "multiple steps + rollback + visibility," orchestration is the answer.

Standard vs. Express: The Same Abstraction, Different Execution Engines

Step Functions has two workflow types, and the exam includes questions that turn on which of the two you choose. Both use the same state language, but the execution engine and the guarantees differ.

ItemStandardExpress
Maximum execution time1 year5 minutes
Execution modelExactly-onceAt-least-once
Throughput2,000 starts/s100,000 starts/s
Execution historyConsole + CloudWatch (90-day lookup)CloudWatch Logs only
BillingPer state transitionExecution time + memory
UseLong/critical workflows (human approval, deployments, orders)Short, frequent event processing (IoT, streams)

The core intuition is this. Use Standard for flows that "take a long time and where getting it right once matters." Examples are a deployment pipeline that waits days for human approval, or an order that must be paid for exactly once. Use Express for flows that are "short, bursty, and idempotent." An example is quickly transforming tens of thousands of events per second. Express being at-least-once means duplicate executions are possible, so the consumer must be idempotent (the same principle we saw with SQS Standard).

⚠️ Trap: If you choose Standard for "processing tens of thousands of short events per second," you get blocked on throughput (2,000/s) and on cost (per-state-transition billing accumulates). The answer is Express. Conversely, for "pay exactly once, waiting days for human approval," Express is unsuitable because of its 5-minute limit and at-least-once, and Standard is the answer. Execution time (1 year vs. 5 minutes) and execution guarantee (exactly-once vs. at-least-once) are the two deciding axes.

Service Integration Patterns: Three Ways to Express Waiting

When a Task state calls an external service, "when does it move on to the next state" differs by pattern. These are the three patterns where the exam is likely to ask you to tell them apart.

PatternURI formatBehavior
Request-Responsearn:aws:states:::lambda:invokeCalls and gets an immediate response, then moves on
Run a Job (.sync)arn:aws:states:::ecs:runTask.syncWaits until the job completes
Wait for Callback (.waitForTaskToken)arn:aws:states:::sqs:sendMessage.waitForTaskTokenWaits until an external party responds with the token

Request-Response is the simplest. You call, and when the response arrives, you're done. .sync is the pattern of "start a long-running job and pause the workflow, waiting until it finishes." ECS tasks or Glue jobs take minutes to hours, and with .sync, Step Functions polls for their completion, waits, and then moves on.

.waitForTaskToken is for cases of waiting for the response of a person or an external system rather than a machine. Step Functions issues a task token along with the task and pauses the workflow. When an external party (a button pressed by an approver, a callback from an external payment provider, etc.) calls SendTaskSuccess/SendTaskFailure with that token, the workflow resumes. It doesn't matter if it takes days (within Standard's 1-year limit).

The classic use of .waitForTaskToken is the human-in-the-loop workflow. When a refund request exceeds a certain amount, the workflow sends an approval email/Slack message (including the token) to a manager and stops. When the manager clicks the approval link, a callback arrives with that token, the workflow resumes, and the refund proceeds. This pattern, which naturally integrates human response time (minutes to days) into the workflow, is hard to implement with a code-based chain, but in Step Functions it is expressed as a single state. The same pattern is used to wait for asynchronous callbacks from external payment gateways or third-party APIs.

The Map state for large-scale parallel processing is also worth knowing.

  • A regular Map applies the same sub-workflow to each item of an array and runs them in parallel.
  • Distributed Map, added in 2022, extends this to the extreme, processing tens of thousands to hundreds of thousands of objects in S3 or a huge JSON array in massive parallel (up to 10,000 concurrent). It is the answer to a scenario like "process 100 million files in an S3 bucket."
  • With a regular Map, the child executions are included in the parent execution's history, so there is a limit on scale. Distributed Map separates each item into a child execution, getting around the parent's state size limit (256KB).
  • Also remember the difference between Parallel (running fixed, different branches at the same time) and Map (repeating the same logic over an array).

AppSync: Declaring the Flow of Data Gathering with GraphQL

If Step Functions made the flow of work declarative, AppSync makes the flow of data gathering declarative. Consider a case where a single mobile screen has to show "user info + recent orders + recommended products." With REST, the client has to call three endpoints separately (over-fetching/under-fetching, multiple round trips) and combine the results. With GraphQL, when the client declares the shape of the data it needs in a single query, the server gathers it from multiple data sources and returns exactly that shape.

type Query {
  getOrder(orderId: ID!): Order      # → DynamoDB resolver
}
type Mutation {
  updateOrderStatus(orderId: ID!, status: String!): Order  # → Lambda resolver
}
type Subscription {
  onOrderStatusUpdate(orderId: ID!): Order
    @aws_subscribe(mutations: ["updateOrderStatus"])       # Real-time subscription
}

The core concept of AppSync is the resolver. It is a function that maps a single GraphQL field to a specific data source (DynamoDB, Lambda, RDS, HTTP, OpenSearch). getOrder reads DynamoDB directly, while updateOrderStatus routes business logic through Lambda, so within one GraphQL schema, each field can use a different backend. It is the AWS implementation of GraphQL's strength of "multiple data sources in one query."

ItemAppSync (GraphQL)API Gateway (REST)
Data fetchingExactly as much as needed in one queryFixed response per endpoint
Multiple sourcesMultiple backends in one queryUsually a single backend
Real-timeBuilt-in subscriptions (WebSocket)WebSocket API configured separately
CachingResponse levelMethod level
Suited forMobile, complex graph queriesGeneral REST APIs

The motivation for GraphQL (published by Facebook in 2015) was the constraints of mobile. On mobile, network round trips are expensive and data costs money, so REST's approach of "calling a fixed, large response per endpoint, multiple times" was inefficient.

  • Solving over-fetching (receiving fields you don't need) and under-fetching (needing multiple calls for one screen, N+1 round trips) at the same time is what GraphQL's declarative query does.
  • GraphQL is not a silver bullet either. On the server side, a single query calls multiple resolvers and can cause an N+1 database problem, so batching such as DataLoader is needed. There is also the criticism that it "moves the client's N+1 to the server's N+1."
  • REST isn't dead; GraphQL's place is "serving complex graph-shaped data to mobile efficiently."

AppSync's real-time subscription (Subscription) is bound to a specific mutation with the @aws_subscribe directive. When the updateOrderStatus mutation runs, AppSync pushes the change over WebSocket to all clients subscribed to that order. This model, where the server pushes changes without polling, is the foundation of chat, real-time dashboards, and collaboration apps. Polling has the waste of "asking continuously even when nothing changes" and the "delay between a change and the next poll"; a subscription pushes exactly once at the moment of change, eliminating both. It flips the problem that SQS long polling, which we saw on Day 1, tried to solve, turning it into push entirely. Authentication supports API_KEY/IAM/Cognito User Pool/OIDC/Lambda Authorizer.

Summary

The one sentence that runs through this article is "take the flow out of the code and make it declarative." Step Functions makes the flow of work explicit as a finite state machine, taking visibility, retries, error handling, and human approval out of the code, and Standard and Express split into "long and exactly-once" versus "short, frequent, idempotent." .sync waits for job completion and .waitForTaskToken waits for an external/human response inside the workflow, while Distributed Map handles massive parallelism. AppSync applies the same spirit to the data layer, declaring the flow of gathering data from multiple backends in a single GraphQL query and pushing changes with real-time subscriptions. Both orchestration and GraphQL are two applications of the same idea: "weave scattered pieces back together, but gather the weaving logic in one place as a declaration rather than as code."

In the next article, we do a scenario-centered comprehensive review of everything covered in Week 11: SQS, SNS, Kinesis, Step Functions, and AppSync.

📝 Practice Questions

Click a choice to reveal the answer and explanation.

Question 1

You need to run 5 Lambda functions in order, compensate (roll back) earlier work if an intermediate step fails, and track the whole flow visually. What is the most appropriate approach?

Question 2

You need a workflow that transforms about 50,000 short IoT events per second. Each execution finishes within a few seconds, and duplicate executions are acceptable through idempotent handling. What is the appropriate Step Functions type?

Question 3

In a refund workflow, manager approval is required above a certain amount, and approval can take days. How do you resume the workflow after approval?

Question 4

You need massively parallel processing that transforms each of hundreds of thousands of objects in an S3 bucket. What is the appropriate Step Functions state?

Question 5

A mobile app needs to efficiently fetch user info (DynamoDB), order history (via Lambda), and recommendations (OpenSearch) for one screen in a single request, and must receive order status changes in real time. What is the appropriate service?

Question 6

Which statement about the difference between Step Functions Standard and Express is correct?

Question 7

What is the core reason GraphQL is more efficient than REST in a mobile environment?

PreviousKinesis: A Log That Holds On to Flowing DataWeek 11 · Day 3Next Week 11 Review: The Questions That Divide the Messaging ModelsWeek 11 · Day 5

Official references

  • DVA-C02 official exam page(opens in a new tab)
  • AWS Step Functions documentation(opens in a new tab)
  • AWS Lambda documentation(opens in a new tab)
  • Amazon S3 documentation(opens in a new tab)
  • Amazon SQS documentation(opens in a new tab)
  • Amazon DynamoDB documentation(opens in a new tab)

On this page

  • Why Take the Workflow Out of the Code: Orchestration vs. Choreography
  • Standard vs. Express: The Same Abstraction, Different Execution Engines
  • Service Integration Patterns: Three Ways to Express Waiting
  • AppSync: Declaring the Flow of Data Gathering with GraphQL
  • Summary
  • Practice Questions