├── .github
└── PULL_REQUEST_TEMPLATE.md
├── .gitignore
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── docs
├── cli-commands.txt
├── guide.md
├── images
│ ├── capabilities.png
│ ├── cfn-output.png
│ ├── paths-breakdown-1.png
│ ├── paths-breakdown-11.png
│ ├── paths-breakdown-2.png
│ ├── paths-breakdown-22.png
│ ├── paths-breakdown-3.png
│ ├── paths-breakdown-33.png
│ ├── paths-breakdown-7.png
│ └── stepdiagram_new.png
└── setup.md
├── inventory-release
├── Makefile
├── go.mod
├── go.sum
├── main.go
└── main_test.go
├── inventory-reserve
├── Makefile
├── go.mod
├── go.sum
├── main.go
└── main_test.go
├── models
├── go.mod
├── go.sum
├── inventory.go
├── order.go
└── payment.go
├── order-new
├── Makefile
├── go.mod
├── go.sum
├── main.go
└── main_test.go
├── order-update
├── Makefile
├── go.mod
├── go.sum
├── main.go
└── main_test.go
├── payment-credit
├── Makefile
├── go.mod
├── go.sum
├── main.go
└── main_test.go
├── payment-debit
├── Makefile
├── go.mod
├── go.sum
├── main.go
└── main_test.go
├── statemachine
└── llt.asl.yaml
├── template.yaml
└── testdata
├── scenario-1.json
├── scenario-2.json
├── scenario-3.json
├── scenario-4.json
├── scenario-5.json
├── scenario-6.json
└── scenario-7.json
/.github/PULL_REQUEST_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | *Issue #, if available:*
2 |
3 | *Description of changes:*
4 |
5 |
6 | By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.
7 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2 | # SPDX-License-Identifier: MIT-0
3 |
4 | .idea/
5 | .aws-sam/
6 | samconfig.toml
7 | tmp
8 | out.txt
9 | packaged.yaml
10 | */**/build
11 |
12 | # Created by https://www.gitignore.io/api/go,visualstudiocode
13 |
14 | ### Go ###
15 | # Binaries for programs and plugins
16 | *.exe
17 | *.exe~
18 | *.dll
19 | *.so
20 | *.dylib
21 |
22 | # Test binary, build with `go test -c`
23 | *.test
24 |
25 | # Output of the go coverage tool, specifically when used with LiteIDE
26 | *.out
27 |
28 | ### Go Patch ###
29 | /vendor/
30 | /Godeps/
31 |
32 | ### VisualStudioCode ###
33 | .vscode/*
34 | # !.vscode/settings.json
35 | # !.vscode/tasks.json
36 | # !.vscode/launch.json
37 | # !.vscode/extensions.json
38 |
39 |
40 | # End of https://www.gitignore.io/api/go,visualstudiocode
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | ## Code of Conduct
2 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct).
3 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact
4 | opensource-codeofconduct@amazon.com with any additional questions or comments.
5 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing Guidelines
2 |
3 | Thank you for your interest in contributing to our project. Whether it's a bug report, new feature, correction, or additional
4 | documentation, we greatly value feedback and contributions from our community.
5 |
6 | Please read through this document before submitting any issues or pull requests to ensure we have all the necessary
7 | information to effectively respond to your bug report or contribution.
8 |
9 |
10 | ## Reporting Bugs/Feature Requests
11 |
12 | We welcome you to use the GitHub issue tracker to report bugs or suggest features.
13 |
14 | When filing an issue, please check [existing open](https://github.com/aws-samples/aws-step-functions-long-lived-transactions/issues), or [recently closed](https://github.com/aws-samples/aws-step-functions-long-lived-transactions/issues?utf8=%E2%9C%93&q=is%3Aissue%20is%3Aclosed%20), issues to make sure somebody else hasn't already
15 | reported the issue. Please try to include as much information as you can. Details like these are incredibly useful:
16 |
17 | * A reproducible test case or series of steps
18 | * The version of our code being used
19 | * Any modifications you've made relevant to the bug
20 | * Anything unusual about your environment or deployment
21 |
22 |
23 | ## Contributing via Pull Requests
24 | Contributions via pull requests are much appreciated. Before sending us a pull request, please ensure that:
25 |
26 | 1. You are working against the latest source on the *master* branch.
27 | 2. You check existing open, and recently merged, pull requests to make sure someone else hasn't addressed the problem already.
28 | 3. You open an issue to discuss any significant work - we would hate for your time to be wasted.
29 |
30 | To send us a pull request, please:
31 |
32 | 1. Fork the repository.
33 | 2. Modify the source; please focus on the specific change you are contributing. If you also reformat all the code, it will be hard for us to focus on your change.
34 | 3. Ensure local tests pass.
35 | 4. Commit to your fork using clear commit messages.
36 | 5. Send us a pull request, answering any default questions in the pull request interface.
37 | 6. Pay attention to any automated CI failures reported in the pull request, and stay involved in the conversation.
38 |
39 | GitHub provides additional document on [forking a repository](https://help.github.com/articles/fork-a-repo/) and
40 | [creating a pull request](https://help.github.com/articles/creating-a-pull-request/).
41 |
42 |
43 | ## Finding contributions to work on
44 | Looking at the existing issues is a great way to find something to contribute on. As our projects, by default, use the default GitHub issue labels (enhancement/bug/duplicate/help wanted/invalid/question/wontfix), looking at any ['help wanted'](https://github.com/aws-samples/aws-step-functions-long-lived-transactions/labels/help%20wanted) issues is a great place to start.
45 |
46 |
47 | ## Code of Conduct
48 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct).
49 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact
50 | opensource-codeofconduct@amazon.com with any additional questions or comments.
51 |
52 |
53 | ## Security issue notifications
54 | If you discover a potential security issue in this project we ask that you notify AWS/Amazon Security via our [vulnerability reporting page](http://aws.amazon.com/security/vulnerability-reporting/). Please do **not** create a public github issue.
55 |
56 |
57 | ## Licensing
58 |
59 | See the [LICENSE](https://github.com/aws-samples/aws-step-functions-long-lived-transactions/blob/master/LICENSE) file for our project's licensing. We will ask you to confirm the licensing of your contribution.
60 |
61 | We may ask you to sign a [Contributor License Agreement (CLA)](http://en.wikipedia.org/wiki/Contributor_License_Agreement) for larger changes.
62 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy of
4 | this software and associated documentation files (the "Software"), to deal in
5 | the Software without restriction, including without limitation the rights to
6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
7 | the Software, and to permit persons to whom the Software is furnished to do so.
8 |
9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
10 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
11 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
12 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
13 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
14 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Managing Long Lived Transactions with AWS Step Functions
2 |
3 | AWS Step Functions is a fully managed Serverless workflow management service for managing long running processes and coordinating the components of distributed applications and microservices using visual workflows. But did you know it can also help you deal with the complexities of dealing with a long lived transaction across distributed components in your microservices architecture? In this Builder session, you will learn how AWS Step Function can help us implement the Saga design pattern.
4 |
5 | ## What problems are we trying to solve?
6 |
7 | When building cloud-based distributed architectures, one of the questions we need to ask ourselves is how do we maintain data consistency across microservices that have their own database / persistence mechanism? We do not have support for Distributed Transaction Coordinators (DTC) or two-phase commit protocols responsible for coordinating transactions across multiple cloud resources. We need a mechanism coordinate multiple local transactions.
8 |
9 | ### What is the Saga pattern?
10 |
11 | A Saga is a design pattern for dealing with “long-lived transactions” (LLT), published by Garcia-Molina and Salem in 1987. Their original paper can be found here [https://www.cs.cornell.edu/andru/cs711/2002fa/reading/sagas.pdf](https://www.cs.cornell.edu/andru/cs711/2002fa/reading/sagas.pdf).
12 |
13 | > “LLT is a saga if it can be written as a sequence of transactions that can be interleaved with other transactions.” (Garcia-Molina, Salem 1987)
14 |
15 | Fundamentally it is a failure management pattern, that provides us the means to establish semantic consistency in our distributed applications by providing compensating transactions for every transaction where you have more than one collaborating services or functions.
16 |
17 | ### Why AWS Step Functions?
18 |
19 | AWS Step Functions provide us with a mechanism for dealing with long-lived transactions, by providing us with the ability to build fully managed state machines that:
20 |
21 | * coordinate the components of distributed applications and microservices
22 | * allowing us to build our state machines using visual workflows
23 | * provides us with a way to manage state and deal with failure
24 |
25 | ## Sample application
26 |
27 | ### Scenario
28 |
29 | You are creating an e-commerce application and are processing an order. This requires you to update order status, process a credit card transaction and update inventory levels. Each state integrates with a different backend with its own local transaction. You need to treat these as a single, distributed transaction.
30 |
31 | 
32 |
33 | ### Learning objectives
34 |
35 | The goal is to demonstrate:
36 |
37 | * How to create a state machine that implements the Saga pattern
38 | * Understand how to use error handling and retry functionality using AWS Step Functions
39 | * Configure Task states to execute pre-provisioned AWS Lambda functions
40 |
41 | ### Get started
42 |
43 | 1. Read the [Setup Information](/docs/setup.md) to deploy the artefacts necessary to complete this session.
44 | 1. Use the [Session Guide](/docs/guide.md) to assist you as you create your saga implementation for the e-commerce application scenario.
45 |
46 | ## Additional Step Functions resources and reference architectures
47 |
48 | * [GitHub: AWS Step Function Samples](https://github.com/aws-samples/aws-stepfunctions-examples/)
49 | * [GitHub: AWS Step Functions Plagiarism Demo .NET Core](https://github.com/aws-samples/aws-step-functions-plagiarism-demo-dotnetcore)
50 | * [Documentation: AWS Step Functions Developer Guide](https://docs.aws.amazon.com/step-functions/latest/dg/welcome.html)
51 | * [Documentation: AWS Step Function Tutorials](https://docs.aws.amazon.com/step-functions/latest/dg/tutorials.html)
52 | * [Specification: Amazon States Language](https://states-language.net/spec.html)
53 | * [Tools: statelint](https://github.com/awslabs/statelint)
54 |
55 |
56 |
57 | ## License Summary
58 |
59 | This sample code is made available under a modified MIT license. See the [LICENSE](LICENSE) file.
60 |
--------------------------------------------------------------------------------
/docs/cli-commands.txt:
--------------------------------------------------------------------------------
1 | TESTING SCENARIOS CLI COMMANDS
2 | --------------------------------------------------
3 | Using your text editor, replace the state-machine-arn and region parameters.
4 |
5 |
6 |
7 | 1 - ErrProcessOrder
8 | -------------------------
9 | aws stepfunctions start-execution \
10 | --state-machine-arn "arn:aws:states:[REGION]:[ACCOUNT NUMBER]:stateMachine:[STATEMACHINE-NAME]" \
11 | --input "{\"order_id\": \"1ae4501d-ed92-4b27-bf0e-fd978ed45127\", \"order_date\": \"2018-10-19T10:50:16+08:00\", \"customer_id\": \"0d52eeef-52a1-4e6e-a5b1-d0515121306c\", \"items\": [{ \"item_id\": \"929\", \"qty\": 3.0, \"description\": \"Cart item 1\", \"unit_price\": 9.99 }]}" \
12 | --region [AWS_REGION]
13 |
14 | 11 - ErrUpdateOrderStatus
15 | -------------------------
16 | aws stepfunctions start-execution \
17 | --state-machine-arn "arn:aws:states:[REGION]:[ACCOUNT NUMBER]:stateMachine:[STATEMACHINE-NAME]" \
18 | --input "{\"order_id\": \"11328abd-368d-43fd-bd4f-db15b5b63951\", \"order_date\": \"2018-10-19T10:50:16+08:00\", \"customer_id\": \"8d04ea6f-c6b2-4422-8550-839a16f01feb\", \"items\": [{ \"item_id\": \"567\", \"qty\": 1.0, \"description\": \"Cart item 1\", \"unit_price\": 199.99 }]}" \
19 | --region [AWS_REGION]
20 |
21 | 2 - ErrProcessPayment
22 | -------------------------
23 | aws stepfunctions start-execution \
24 | --state-machine-arn "arn:aws:states:[REGION]:[ACCOUNT NUMBER]:stateMachine:[STATEMACHINE-NAME]" \
25 | --input "{\"order_id\": \"20b0b599-441b-45c3-910e-ad63fe992c43\", \"order_date\": \"2018-10-19T10:50:16+08:00\", \"customer_id\": \"151ae48f-79b0-47b6-a8a6-bd8dbcf9af9a\", \"items\": [{ \"item_id\": \"423\", \"qty\": 10.0, \"description\": \"Cart item 1\", \"unit_price\": 34.99 }]}" \
26 | --region [AWS_REGION]
27 |
28 | 22 - ErrProcessRefund
29 | -------------------------
30 | aws stepfunctions start-execution \
31 | --state-machine-arn "arn:aws:states:[REGION]:[ACCOUNT NUMBER]:stateMachine:[STATEMACHINE-NAME]" \
32 | --input "{\"order_id\": \"222f741b-0292-4f93-a2f7-503f92486955 \", \"order_date\": \"2018-10-19T10:50:16+08:00\", \"customer_id\": \"227dd3c9-58ab-4f0d-958a-5ead5858fba8\", \"items\": [{ \"item_id\": \"655\", \"qty\": 2.0, \"description\": \"Cart item 1\", \"unit_price\": 99.99 }]}" \
33 | --region [AWS_REGION]
34 |
35 | 3 - ErrReserveInventory
36 | -------------------------
37 | aws stepfunctions start-execution \
38 | --state-machine-arn "arn:aws:states:[REGION]:[ACCOUNT NUMBER]:stateMachine:[STATEMACHINE-NAME]" \
39 | --input "{\"order_id\": \"3a7dc768-6f32-495d-a140-3d330c246f50\", \"order_date\": \"2018-10-19T10:50:16+08:00\", \"customer_id\": \"aa226136-bd50-4718-8e87-6962c8d34779\", \"items\": [{ \"item_id\": \"765\", \"qty\": 1.0, \"description\": \"Cart item 1\", \"unit_price\": 6.50 }]}" \
40 | --region [AWS_REGION]
41 |
42 | 33 - ErrReleaseInventory
43 | -------------------------
44 | aws stepfunctions start-execution \
45 | --state-machine-arn "arn:aws:states:[REGION]:[ACCOUNT NUMBER]:stateMachine:[STATEMACHINE-NAME]" \
46 | --input "{\"order_id\": \"33a49007-a815-4079-9b9b-e30ae7eca11f\", \"order_date\": \"2018-10-19T10:50:16+08:00\", \"customer_id\": \"39081ebf-16a9-4e2c-a88b-d1a4c76956fd\", \"items\": [{ \"item_id\": \"567\", \"qty\": 1.0, \"description\": \"Cart item 1\", \"unit_price\": 199.99 }]}" \
47 | --region [AWS_REGION]
48 |
49 | 4 to 9 - No error
50 | -------------------------
51 | aws stepfunctions start-execution \
52 | --state-machine-arn "arn:aws:states:[REGION]:[ACCOUNT NUMBER]:stateMachine:[STATEMACHINE-NAME]" \
53 | --input "{\"order_id\": \"47063fe3-56d9-4c51-b91f-71929834ce03\", \"order_date\": \"2018-10-19T10:50:16+08:00\", \"customer_id\": \"3b27c7c4-7a3e-4635-aef9-6b5c74de6465\", \"items\": [{ \"item_id\": \"988\", \"qty\": 100.0, \"description\": \"Cart item 1\", \"unit_price\": 0.99 }]}" \
54 | --region [AWS_REGION]
--------------------------------------------------------------------------------
/docs/guide.md:
--------------------------------------------------------------------------------
1 | # Session Guide
2 |
3 | ## What's in this repository?
4 |
5 | This is a sample template for Managing Long Lived Transactions with AWS Step Functions. Below is a brief explanation of what we have created for you:
6 |
7 | ``` bash
8 | .
9 | ├── CODE_OF_CONDUCT.md
10 | ├── CONTRIBUTING.md
11 | ├── LICENSE
12 | ├── README.md
13 | ├── docs <-- # Workshop guide and setup instructions
14 | ├── inventory-release <-- # Lambda function code represents compensating transaction to release inventory
15 | │ ├── ...
16 | │ └── main.go
17 | ├── inventory-reserve <-- # Lambda function code represents compensating transaction to release inventory
18 | │ ├── ...
19 | │ └── main.go
20 | ├── models <-- # Models package that defines the types used by the various functions and state data
21 | │ ├── ...
22 | │ ├── inventory.go
23 | │ ├── order.go
24 | │ └── payment.go
25 | ├── order-new <-- # Lambda function code represents task to create a new order and set status to "new order"
26 | │ ├── ...
27 | │ └── main.go
28 | ├── order-update <-- # Lambda function code represents compensating transaction for orders.
29 | │ ├── ... # Sets order status to "pending"
30 | │ └── main.go
31 | ├── payment-credit <-- # Lambda function code represents the compensating transaction to refund customer order
32 | │ ├── ...
33 | │ └── main.go
34 | ├── payment-debit <-- # Lambda function code represents task to process financial transaction for the order
35 | │ ├── ...
36 | │ └── main.go
37 | ├── statemachine
38 | │ └── llt.asl.yaml <-- # Step Functions ASL template
39 | ├── template.yaml <-- # AWS SAM template for defining and deploying serverless application resources
40 | └── ...
41 |
42 | ```
43 |
44 | ## Amazon States Language
45 |
46 | A full description of the how to describe your state machine can be found on the [Amazon States Language specification](https://states-language.net/spec.html).
47 |
48 | Please review the "Templates" section in the [AWS Console](https://console.aws.amazon.com/states/home) for examples of how you can implement various states.
49 |
50 | ### Useful snippets
51 |
52 | #### Task state
53 |
54 | The Task State (identified by "Type":"Task") causes the interpreter to execute the work identified by the state's “Resource” field.
55 |
56 | ```json
57 | "ProcessOrder": {
58 | "Comment": "First transaction to save the order and set the order status to new",
59 | "Type": "Task",
60 | "Resource": "arn:aws:lambda:[REGION]:[ACCOUNT NUMBER]:function:aws-step-functions-long-lived-tra-NewOrderFunction-121DONKVIBL5T",
61 | "TimeoutSeconds": 10,
62 | "Next": "ProcessPayment"
63 | }
64 | ```
65 |
66 | #### Catch
67 | Any state can encounter runtime errors. Errors can arise because of state machine definition issues (e.g. the “ResultPath” problem discussed immediately above), task failures (e.g. an exception thrown by a Lambda function) or because of transient issues, such as network partition events.
68 |
69 | ```json
70 | "Catch": [
71 | {
72 | "ErrorEquals": ["ErrProcessOrder"],
73 | "ResultPath": "$.error",
74 | "Next": "UpdateOrderStatus"
75 | }
76 | ]
77 | ```
78 |
79 | #### Retry
80 | Task States and Parallel States MAY have a field named “Retry”, whose value MUST be an array of objects, called Retriers.
81 |
82 | When a state reports an error, the interpreter scans through the Retriers and, when the Error Name appears in the value of of a Retrier’s “ErrorEquals” field, implements the retry policy described in that Retrier.
83 |
84 | ```json
85 | "Retry": [{
86 | "ErrorEquals": ["States.ALL"],
87 | "IntervalSeconds": 1,
88 | "MaxAttempts": 2,
89 | "BackoffRate": 2.0
90 | }],
91 | "Catch": [{
92 | "ErrorEquals": ["ErrReleaseInventory"],
93 | "ResultPath": "$.error",
94 | "Next": "ReleaseInventoryFailed"
95 | }
96 | ]
97 | ```
98 |
99 | ## Custom Errors
100 |
101 | The following is a list of all the custom errors thrown by the application and can be used in your state machine.
102 |
103 | * `ErrProcessOrder` represents a process order error
104 | * `ErrUpdateOrderStatus` represents a process order error
105 | * `ErrProcessPayment` represents a process payment error
106 | * `ErrProcessRefund` represents a process payment refund error
107 | * `ErrReserveInventory` represents a inventory update error
108 | * `ErrReleaseInventory` represents a inventory update reversal error
109 |
110 | ## Testing Scenarios
111 |
112 | The AWS Step Functions implementation has been configured for you to be easily test the various scenarios of the saga implementation. Modifying your `order_id` with a specified prefix will trigger an error in the each Task.
113 |
114 | OrderID Prefix | Will error with | Example | Expected execution
115 | ------------ | ------------- | --- | ---
116 | 1 | ErrProcessOrder | 1ae4501d-ed92-4b27-bf0e-fd978ed45127 | 
117 | 11 | ErrUpdateOrderStatus | 11328abd-368d-43fd-bd4f-db15b5b63951 | 
118 | 2 | ErrProcessPayment | 20b0b599-441b-45c3-910e-ad63fe992c43 | 
119 | 22 | ErrProcessRefund | 222f741b-0292-4f93-a2f7-503f92486955 | 
120 | 3 | ErrReserveInventory | 3a7dc768-6f32-495d-a140-3d330c246f50 | 
121 | 33 | ErrReleaseInventory | 33a49007-a815-4079-9b9b-e30ae7eca11f | 
122 | 4-9 | No error | 47063fe3-56d9-4c51-b91f-71929834ce03 | 
123 |
124 | ### Invoking your Step Function via CLI
125 |
126 | The AWS CLI command will trigger a execution of your state machine. Make sure you substitute the ARN for the state machine in your account. You can find the ARN in the AWS CloudFormation Output section or in the AWS Step Functions console.
127 |
128 | 
129 |
130 | > `--region` must match the region you have deployed the application stack into. This is optional if you're using your default region.
131 |
132 | ``` bash
133 | aws stepfunctions start-execution \
134 | --state-machine-arn "arn:aws:states:[REGION]:[ACCOUNT NUMBER]:stateMachine:[STATEMACHINE-NAME]" \
135 | --input "{\"order_id\": \"40063fe3-56d9-4c51-b91f-71929834ce03\", \"order_date\": \"2018-10-19T10:50:16+08:00\", \"customer_id\": \"8d04ea6f-c6b2-4422-8550-839a16f01feb\", \"items\": [{ \"item_id\": \"567\", \"qty\": 1.0, \"description\": \"Cart item 1\", \"unit_price\": 199.99 }]}" \
136 | --region [AWS_REGION]
137 | ```
138 |
139 | **[DOWNLOAD SCENARIO CLI COMMANDS](cli-commands.txt)**
140 |
141 | ## How else can you implement this solution?
142 |
143 | Is there any other way you can think of how to break this problem down? What other features of Step Functions could be employed to implement a saga pattern?
144 |
--------------------------------------------------------------------------------
/docs/images/capabilities.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aws-samples/aws-step-functions-long-lived-transactions/daacbd57fa307b9f65a55dd936a2547a2d027f59/docs/images/capabilities.png
--------------------------------------------------------------------------------
/docs/images/cfn-output.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aws-samples/aws-step-functions-long-lived-transactions/daacbd57fa307b9f65a55dd936a2547a2d027f59/docs/images/cfn-output.png
--------------------------------------------------------------------------------
/docs/images/paths-breakdown-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aws-samples/aws-step-functions-long-lived-transactions/daacbd57fa307b9f65a55dd936a2547a2d027f59/docs/images/paths-breakdown-1.png
--------------------------------------------------------------------------------
/docs/images/paths-breakdown-11.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aws-samples/aws-step-functions-long-lived-transactions/daacbd57fa307b9f65a55dd936a2547a2d027f59/docs/images/paths-breakdown-11.png
--------------------------------------------------------------------------------
/docs/images/paths-breakdown-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aws-samples/aws-step-functions-long-lived-transactions/daacbd57fa307b9f65a55dd936a2547a2d027f59/docs/images/paths-breakdown-2.png
--------------------------------------------------------------------------------
/docs/images/paths-breakdown-22.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aws-samples/aws-step-functions-long-lived-transactions/daacbd57fa307b9f65a55dd936a2547a2d027f59/docs/images/paths-breakdown-22.png
--------------------------------------------------------------------------------
/docs/images/paths-breakdown-3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aws-samples/aws-step-functions-long-lived-transactions/daacbd57fa307b9f65a55dd936a2547a2d027f59/docs/images/paths-breakdown-3.png
--------------------------------------------------------------------------------
/docs/images/paths-breakdown-33.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aws-samples/aws-step-functions-long-lived-transactions/daacbd57fa307b9f65a55dd936a2547a2d027f59/docs/images/paths-breakdown-33.png
--------------------------------------------------------------------------------
/docs/images/paths-breakdown-7.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aws-samples/aws-step-functions-long-lived-transactions/daacbd57fa307b9f65a55dd936a2547a2d027f59/docs/images/paths-breakdown-7.png
--------------------------------------------------------------------------------
/docs/images/stepdiagram_new.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aws-samples/aws-step-functions-long-lived-transactions/daacbd57fa307b9f65a55dd936a2547a2d027f59/docs/images/stepdiagram_new.png
--------------------------------------------------------------------------------
/docs/setup.md:
--------------------------------------------------------------------------------
1 | # Setup Information
2 |
3 | ## Using AWS CloudFormation (preferred)
4 |
5 | The easiest way to get started is to launch an AWS CloudFormation template that will deploy the resources for this workshop.
6 |
7 | Region| Launch
8 | ------|-----
9 | US East (N. Virginia) | [](https://console.aws.amazon.com/cloudformation/home?region=us-east-1#/stacks/create/review?stackName=aws-sfn-saga&templateURL=https://s3.amazonaws.com/aws-step-functions-long-lived-transactions-us-east-1/template.yaml)
10 | US West (Oregon) | [](https://console.aws.amazon.com/cloudformation/home?region=us-west-2#/stacks/create/review?stackName=aws-sfn-saga&templateURL=https://s3-us-west-2.amazonaws.com/aws-step-functions-long-lived-transactions-us-west-2/template.yaml)
11 | Asia Pacific (Sydney) | [](https://console.aws.amazon.com/cloudformation/home?region=ap-southeast-2#/stacks/create/review?stackName=aws-sfn-saga&templateURL=https://s3-ap-southeast-2.amazonaws.com/aws-step-functions-long-lived-transactions-ap-southeast-2/template.yaml)
12 |
13 | ### CloudFormation Setup Instructions
14 |
15 | 1. Click the **Launch Stack** link above for the region of your choice.
16 |
17 | 1. Name the stack (or leave the default `aws-sfn-saga`)
18 |
19 | 1. In the Capabilities section acknowledge that CloudFormation will create IAM resources and click **Create**.
20 | 
21 |
22 | 1. Select `Create Change Set`
23 |
24 | 1. Once the Change Set has been successfully created, select `Execute` to create the stack.
25 |
26 | ## Deploy from Source
27 | Alternatively, you can deploy the source from you local development environment. Please note, this requires the following environment setup.
28 |
29 | ### Requirements
30 |
31 | * [aws-cli](https://aws.amazon.com/cli/) already configured with Administrator permissions.
32 | * [sam-cli](https://docs.aws.amazon.com/serverless-application-model/index.html) AWS SAM CLI tool for local development and testing of Serverless applications
33 | * [Docker installed](https://www.docker.com/community-edition)
34 | * [Golang](https://golang.org)
35 | * Make (see instructions below)
36 |
37 | ### Installing SAM CLI
38 |
39 | AWS SAM provides you with a command line tool, the AWS SAM CLI, that makes it easy for you to create and manage serverless applications. You need to install and configure a few things in order to use the AWS SAM CLI.
40 |
41 | To install the AWS SAM CLI, see the following instructions for your development host:
42 |
43 | * [Installing the AWS SAM CLI on Linux](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-install-linux.html)
44 | * [Installing the AWS SAM CLI on Windows](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-install-windows.html)
45 | * [Installing the AWS SAM CLI on macOS](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-install-mac.html)
46 |
47 | ### Installing Golang
48 |
49 | Please ensure Go 1.x (where 'x' is the latest version) is installed as per the instructions on the official golang website: https://golang.org/doc/install
50 |
51 | A quick-start way would be to use Homebrew, chocolatey or your linux package manager.
52 |
53 | #### Configuring GoPATH
54 |
55 | In order to build the source locally you need to set up our Go development environment.
56 |
57 | Follow the instructions as outlined here https://github.com/golang/go/wiki/SettingGOPATH
58 |
59 | ### Clone the repository
60 |
61 | Once you have you GOPATH configured clone the builder session repository into the following directory under your GOPATH
62 |
63 | ```shell
64 | mkdir $GOPATH/src/github.com/aws-samples
65 | cd $GOPATH/src/github.com/aws-samples
66 | git clone https://github.com/aws-samples/aws-step-functions-long-lived-transactions.git
67 | ```
68 |
69 | once you have done that download and install the dependencies for the project. From the project root run:
70 |
71 | ```shell
72 | go get -u ./...
73 | ```
74 |
75 | ### Deploy the sample application
76 | To build and deploy your application for the first time, run the following in your shell:
77 |
78 | ```shell
79 | sam build
80 | sam deploy --guided
81 |
82 | Configuring SAM deploy
83 | ======================
84 |
85 | Looking for config file [samconfig.toml] : Found
86 | Reading default arguments : Success
87 |
88 | Setting default arguments for 'sam deploy'
89 | =========================================
90 | Stack Name [sfn-saga]:
91 | AWS Region [ap-southeast-2]:
92 | #Shows you resources changes to be deployed and require a 'Y' to initiate deploy
93 | Confirm changes before deploy [y/N]: N
94 | #SAM needs permission to be able to create roles to connect to the resources in your template
95 | Allow SAM CLI IAM role creation [Y/n]: Y
96 | Save arguments to configuration file [Y/n]: Y
97 | SAM configuration file [samconfig.toml]:
98 | SAM configuration environment [default]:
99 | ```
100 |
101 | The first command will build the source of your application. The second command will package and deploy your application to AWS, with a series of prompts:
102 |
103 | * **Stack Name**: The name of the stack to deploy to CloudFormation. This should be unique to your account and region, and a good starting point would be something matching your project name.
104 |
105 | * **AWS Region**: The AWS region you want to deploy your app to.
106 |
107 | * **Confirm changes before deploy**: If set to yes, any change sets will be shown to you before execution for manual review. If set to no, the AWS SAM CLI will automatically deploy application changes.
108 |
109 | * **Allow SAM CLI IAM role creation**: Many AWS SAM templates, including this example, create AWS IAM roles required for the AWS Lambda function(s) included to access AWS services. By default, these are scoped down to minimum required permissions. To deploy an AWS CloudFormation stack which creates or modifies IAM roles, the `CAPABILITY_IAM` value for `capabilities` must be provided. If permission isn't provided through this prompt, to deploy this example you must explicitly pass `--capabilities CAPABILITY_IAM` to the `sam deploy` command.
110 |
111 | * **Save arguments to samconfig.toml**: If set to yes, your choices will be saved to a configuration file inside the project, so that in the future you can just re-run `sam deploy` without parameters to deploy changes to your application.
112 |
113 | The following command describes the outputs defined within the cloudformation stack:
114 |
115 | ```shell
116 | aws cloudformation describe-stacks \
117 | --stack-name aws-sfn-saga --query 'Stacks[].Outputs'
118 | ```
119 |
120 | ## Completion
121 |
122 | Once you have successfully deployed the functions, go ahead and start testing the saga.
123 |
124 | See the [Session Guide](guide.md) for more information.
125 |
126 | ## Clean up
127 |
128 | To delete the sample application that you created, use the AWS CLI. Assuming you used your project name for the stack name, you can run the following:
129 |
130 | ```shell
131 | aws cloudformation delete-stack --stack-name aws-sfn-saga
132 | ```
133 |
--------------------------------------------------------------------------------
/inventory-release/Makefile:
--------------------------------------------------------------------------------
1 | .PHONY: build-ReleaseInventoryFunction
2 |
3 | build-ReleaseInventoryFunction:
4 | GOOS=linux go build -o bootstrap
5 | cp ./bootstrap $(ARTIFACTS_DIR)/.
--------------------------------------------------------------------------------
/inventory-release/go.mod:
--------------------------------------------------------------------------------
1 | module aws-step-functions-long-lived-transactions/inventory-release
2 |
3 | go 1.16
4 |
5 | require (
6 | aws-step-functions-long-lived-transactions/models v0.0.0-00010101000000-000000000000
7 | github.com/andybalholm/brotli v1.0.3 // indirect
8 | github.com/aws/aws-lambda-go v1.24.0
9 | github.com/aws/aws-sdk-go v1.38.70
10 | github.com/aws/aws-xray-sdk-go v1.5.0
11 | github.com/klauspost/compress v1.13.1 // indirect
12 | github.com/stretchr/testify v1.6.1
13 | github.com/urfave/cli v1.22.1 // indirect
14 | github.com/valyala/fasthttp v1.28.0 // indirect
15 | golang.org/x/net v0.0.0-20210614182718-04defd469f4e // indirect
16 | golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c // indirect
17 | google.golang.org/genproto v0.0.0-20210630183607-d20f26d13c79 // indirect
18 | google.golang.org/grpc v1.39.0 // indirect
19 | )
20 |
21 | replace aws-step-functions-long-lived-transactions/models => ../models
22 |
--------------------------------------------------------------------------------
/inventory-release/go.sum:
--------------------------------------------------------------------------------
1 | cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
2 | cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
3 | dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
4 | github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
5 | github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
6 | github.com/DATA-DOG/go-sqlmock v1.2.0/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM=
7 | github.com/DATA-DOG/go-sqlmock v1.4.0 h1:yxQ63CFIA8Sxkh0vqIofuNrsXl/LZ42TpeTLV4Nb5HM=
8 | github.com/DATA-DOG/go-sqlmock v1.4.0/go.mod h1:3TucWNLPFOLcHhha1CPp7Kis1UG2h/AqGROPyOeZzsM=
9 | github.com/DATA-DOG/go-sqlmock v1.4.1/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM=
10 | github.com/andybalholm/brotli v1.0.1/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y=
11 | github.com/andybalholm/brotli v1.0.2/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y=
12 | github.com/andybalholm/brotli v1.0.3 h1:fpcw+r1N1h0Poc1F/pHbW40cUm/lMEQslZtCkBQ0UnM=
13 | github.com/andybalholm/brotli v1.0.3/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
14 | github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
15 | github.com/aws/aws-lambda-go v1.13.2 h1:8lYuRVn6rESoUNZXdbCmtGB4bBk4vcVYojiHjE4mMrM=
16 | github.com/aws/aws-lambda-go v1.13.2/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU=
17 | github.com/aws/aws-lambda-go v1.24.0 h1:bOMerM175hLqHLdF1Nonfv1NA20nTIatuC0HK8eMoYg=
18 | github.com/aws/aws-lambda-go v1.24.0/go.mod h1:jJmlefzPfGnckuHdXX7/80O3BvUUi12XOkbv4w9SGLU=
19 | github.com/aws/aws-sdk-go v1.17.12/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
20 | github.com/aws/aws-sdk-go v1.25.26 h1:hMrxW3feteaGcP32oKaFdCQsCEWYf9zF12g73C0AcbI=
21 | github.com/aws/aws-sdk-go v1.25.26/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
22 | github.com/aws/aws-sdk-go v1.38.70 h1:EGHVUQzHIxQDF9LwQU22yE9bJd1HuBAWpJYSEnxnnhc=
23 | github.com/aws/aws-sdk-go v1.38.70/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro=
24 | github.com/aws/aws-xray-sdk-go v1.0.0-rc.14 h1:cxRNHoaVNiGhCddLe7A20nVFJsoWhs1jADm/1M97Ytw=
25 | github.com/aws/aws-xray-sdk-go v1.0.0-rc.14/go.mod h1:NCf+n91lACeo8klrI7RsKqDaAEXt321d/cfaJk4YuDM=
26 | github.com/aws/aws-xray-sdk-go v1.5.0 h1:/5uJ14/opeVzPGULnv3lYpqy8d47LKCxdm60m11dOVI=
27 | github.com/aws/aws-xray-sdk-go v1.5.0/go.mod h1:Ig1ouBiDz+jmMiufD7HHNFN+7ijGPbY53UZRir7Cu7Y=
28 | github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
29 | github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
30 | github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
31 | github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
32 | github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
33 | github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
34 | github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
35 | github.com/davecgh/go-spew v0.0.0-20160907170601-6d212800a42e/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
36 | github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
37 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
38 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
39 | github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
40 | github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
41 | github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
42 | github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
43 | github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
44 | github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ=
45 | github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
46 | github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
47 | github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
48 | github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
49 | github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
50 | github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
51 | github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw=
52 | github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
53 | github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
54 | github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
55 | github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
56 | github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
57 | github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
58 | github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
59 | github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
60 | github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
61 | github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
62 | github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
63 | github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
64 | github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
65 | github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
66 | github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
67 | github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
68 | github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
69 | github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
70 | github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
71 | github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
72 | github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
73 | github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
74 | github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
75 | github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
76 | github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
77 | github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
78 | github.com/grpc-ecosystem/go-grpc-middleware v1.2.2/go.mod h1:EaizFBKfUKtMIF5iaDEhniwNedqGo9FuLFzppDr3uwI=
79 | github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
80 | github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM=
81 | github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
82 | github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
83 | github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
84 | github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
85 | github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
86 | github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
87 | github.com/klauspost/compress v1.11.8/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
88 | github.com/klauspost/compress v1.12.2/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg=
89 | github.com/klauspost/compress v1.13.1 h1:wXr2uRxZTJXHLly6qhJabee5JqIhTRoLBhDOA74hDEQ=
90 | github.com/klauspost/compress v1.13.1/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg=
91 | github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
92 | github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
93 | github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
94 | github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
95 | github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
96 | github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
97 | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
98 | github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
99 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
100 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
101 | github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
102 | github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
103 | github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
104 | github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
105 | github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
106 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
107 | github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
108 | github.com/stretchr/testify v1.1.4/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
109 | github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
110 | github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
111 | github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
112 | github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
113 | github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
114 | github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
115 | github.com/urfave/cli/v2 v2.2.0/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ=
116 | github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
117 | github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
118 | github.com/valyala/fasthttp v1.24.0/go.mod h1:0mw2RjXGOzxf4NL2jni3gUQ7LfjjUSiG5sskOUUSEpU=
119 | github.com/valyala/fasthttp v1.28.0 h1:ruVmTmZaBR5i67NqnjvvH5gEv0zwHfWtbjoyW98iho4=
120 | github.com/valyala/fasthttp v1.28.0/go.mod h1:cmWIqlu99AO/RKcp1HWaViTqc57FswJOfYYdPJBl8BA=
121 | github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio=
122 | github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc=
123 | github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
124 | go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
125 | go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
126 | go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
127 | go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
128 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
129 | golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
130 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
131 | golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
132 | golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
133 | golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
134 | golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
135 | golang.org/x/exp v0.0.0-20200331195152-e8c3332aa8e5/go.mod h1:4M0jN8W1tt0AVLNr8HDosyJCDCDuyL9N9+3m7wDWgKw=
136 | golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
137 | golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
138 | golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
139 | golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
140 | golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
141 | golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
142 | golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
143 | golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
144 | golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
145 | golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
146 | golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
147 | golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
148 | golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
149 | golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
150 | golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
151 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
152 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
153 | golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553 h1:efeOvDhwQ29Dj3SdAV/MJf8oukgn+8D8WgaCaRMchF8=
154 | golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
155 | golang.org/x/net v0.0.0-20200421231249-e086a090c8fd/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
156 | golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
157 | golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
158 | golang.org/x/net v0.0.0-20210226101413-39120d07d75e/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
159 | golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
160 | golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
161 | golang.org/x/net v0.0.0-20210510120150-4163338589ed/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
162 | golang.org/x/net v0.0.0-20210614182718-04defd469f4e h1:XpT3nA5TvE525Ne3hInMh6+GETgn27Zfm9dxsThnX2Q=
163 | golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
164 | golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
165 | golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
166 | golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
167 | golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
168 | golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
169 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
170 | golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
171 | golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
172 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
173 | golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
174 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
175 | golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
176 | golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
177 | golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
178 | golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
179 | golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
180 | golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
181 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
182 | golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
183 | golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
184 | golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
185 | golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
186 | golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
187 | golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c h1:F1jZWGFhYfh0Ci55sIpILtKKK8p3i2/krTr0H1rg74I=
188 | golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
189 | golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
190 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
191 | golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
192 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
193 | golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
194 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
195 | golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
196 | golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
197 | golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
198 | golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
199 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
200 | golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
201 | golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
202 | golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
203 | golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
204 | golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
205 | golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
206 | golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
207 | golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
208 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
209 | golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
210 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
211 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
212 | google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
213 | google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
214 | google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
215 | google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
216 | google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
217 | google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
218 | google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
219 | google.golang.org/genproto v0.0.0-20210114201628-6edceaf6022f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
220 | google.golang.org/genproto v0.0.0-20210630183607-d20f26d13c79 h1:s1jFTXJryg4a1mew7xv03VZD8N9XjxFhk1o4Js4WvPQ=
221 | google.golang.org/genproto v0.0.0-20210630183607-d20f26d13c79/go.mod h1:yiaVoXHpRzHGyxV3o4DktVWY4mSUErTKaeEOq6C3t3U=
222 | google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
223 | google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
224 | google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
225 | google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
226 | google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
227 | google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
228 | google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
229 | google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
230 | google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
231 | google.golang.org/grpc v1.39.0 h1:Klz8I9kdtkIN6EpHHUOMLCYhTn/2WAe5a0s1hcBkdTI=
232 | google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE=
233 | google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
234 | google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
235 | google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
236 | google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
237 | google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
238 | google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
239 | google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
240 | google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
241 | google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
242 | google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
243 | google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
244 | google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
245 | google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ=
246 | google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
247 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
248 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
249 | gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
250 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
251 | gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
252 | gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
253 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
254 | gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
255 | honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
256 | honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
257 |
--------------------------------------------------------------------------------
/inventory-release/main.go:
--------------------------------------------------------------------------------
1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2 | // SPDX-License-Identifier: MIT-0
3 | package main
4 |
5 | import (
6 | "context"
7 | "fmt"
8 | "log"
9 | "os"
10 |
11 | "aws-step-functions-long-lived-transactions/models" // local
12 |
13 | "github.com/aws/aws-lambda-go/lambda"
14 | "github.com/aws/aws-sdk-go/aws"
15 | "github.com/aws/aws-sdk-go/aws/awserr"
16 | "github.com/aws/aws-sdk-go/aws/session"
17 | "github.com/aws/aws-sdk-go/service/dynamodb"
18 | "github.com/aws/aws-sdk-go/service/dynamodb/dynamodbattribute"
19 | "github.com/aws/aws-xray-sdk-go/xray"
20 | )
21 |
22 | var dynamoDB *dynamodb.DynamoDB
23 |
24 | func init() {
25 |
26 | // Create DynamoDB client
27 | var awscfg = &aws.Config{
28 | Region: aws.String(os.Getenv("AWS_REGION")),
29 | }
30 | var sess = session.Must(session.NewSession(awscfg))
31 | dynamoDB = dynamodb.New(sess)
32 |
33 | // AWS X-Ray for AWS SDK trace
34 | xray.AWS(dynamoDB.Client)
35 |
36 | log.SetPrefix("TRACE: ")
37 | log.SetFlags(log.Ldate | log.Ltime)
38 |
39 | }
40 |
41 | func handler(ctx context.Context, ord models.Order) (models.Order, error) {
42 |
43 | log.Printf("[%s] - processing inventory release", ord.OrderID)
44 |
45 | // Find inventory transaction
46 | inventory, err := getTransaction(ctx, ord.OrderID)
47 | if err != nil {
48 | log.Printf("[%s] - error! %s", ord.OrderID, err.Error())
49 | return models.Order{}, models.NewErrReleaseInventory(err.Error())
50 | }
51 |
52 | // release the items to the inventory
53 | inventory.Release()
54 |
55 | // save the inventory transaction
56 | err = saveTransaction(ctx, inventory)
57 | if err != nil {
58 | log.Printf("[%s] - error! %s", ord.OrderID, err.Error())
59 | return ord, models.NewErrReleaseInventory(err.Error())
60 | }
61 |
62 | ord.Inventory = inventory
63 |
64 | // testing scenario
65 | if ord.OrderID[0:2] == "33" {
66 | return ord, models.NewErrReleaseInventory("Unable to release inventory for order " + ord.OrderID)
67 | }
68 |
69 | log.Printf("[%s] - reservation processed", ord.OrderID)
70 |
71 | return ord, nil
72 | }
73 |
74 | func getTransaction(ctx context.Context, orderID string) (models.Inventory, error) {
75 |
76 | inventory := models.Inventory{}
77 |
78 | input := &dynamodb.QueryInput{
79 | ExpressionAttributeValues: map[string]*dynamodb.AttributeValue{
80 | ":v1": {
81 | S: aws.String(orderID),
82 | },
83 | ":v2": {
84 | S: aws.String("Reserve"),
85 | },
86 | },
87 | KeyConditionExpression: aws.String("order_id = :v1 AND transaction_type = :v2"),
88 | TableName: aws.String(os.Getenv("TABLE_NAME")),
89 | IndexName: aws.String("orderIDIndex"),
90 | }
91 |
92 | // Get payment transaction from database
93 | result, err := dynamoDB.QueryWithContext(ctx, input)
94 | if err != nil {
95 | return inventory, err
96 | }
97 |
98 | err = dynamodbattribute.UnmarshalMap(result.Items[0], &inventory)
99 | if err != nil {
100 | return inventory, fmt.Errorf("failed to DynamoDB unmarshal Record, %v", err.(awserr.Error))
101 | }
102 |
103 | return inventory, nil
104 | }
105 |
106 | func saveTransaction(ctx context.Context, inventory models.Inventory) error {
107 |
108 | marshalledInventory, err := dynamodbattribute.MarshalMap(inventory)
109 | if err != nil {
110 | return fmt.Errorf("failed to DynamoDB marshal Inventory, %v", err)
111 | }
112 |
113 | _, err = dynamoDB.PutItemWithContext(ctx, &dynamodb.PutItemInput{
114 | TableName: aws.String(os.Getenv("TABLE_NAME")),
115 | Item: marshalledInventory,
116 | })
117 |
118 | if err != nil {
119 | return fmt.Errorf("failed to put record to DynamoDB, %v", err)
120 | }
121 | return nil
122 | }
123 |
124 | func main() {
125 | lambda.Start(handler)
126 | }
127 |
--------------------------------------------------------------------------------
/inventory-release/main_test.go:
--------------------------------------------------------------------------------
1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2 | // SPDX-License-Identifier: MIT-0
3 | package main
4 |
5 | import (
6 | "encoding/json"
7 | "fmt"
8 | "os"
9 | "reflect"
10 | "testing"
11 |
12 | "aws-step-functions-long-lived-transactions/models"
13 |
14 | "github.com/stretchr/testify/assert"
15 | )
16 |
17 | // Test Orders
18 | var scenarioErrProcessRefund = "../testdata/scenario-4.json"
19 | var scenarioSuccessfulOrder = "../testdata/scenario-7.json"
20 |
21 | func TestHandler(t *testing.T) {
22 | assert := assert.New(t)
23 |
24 | t.Run("ProcessRefund", func(t *testing.T) {
25 |
26 | input := parseOrder(scenarioSuccessfulOrder)
27 | input.OrderID = "77063fe3-56d9-4c51-b91f-71929834ce03"
28 |
29 | order, err := handler(nil, input)
30 | if err != nil {
31 | t.Fatal("Error failed to trigger with an invalid request")
32 | }
33 |
34 | assert.NotEmpty(order.Inventory.TransactionID, "TransactionID must not be empty")
35 | })
36 |
37 | }
38 |
39 | func TestErrorIsOfTypeErrProcessRefund(t *testing.T) {
40 | assert := assert.New(t)
41 | t.Run("ErrProcessRefund", func(t *testing.T) {
42 |
43 | input := parseOrder(scenarioErrProcessRefund)
44 |
45 | order, err := handler(nil, input)
46 | if err != nil {
47 | fmt.Print(err)
48 | }
49 |
50 | if assert.Error(err) {
51 | errorType := reflect.TypeOf(err)
52 | assert.Equal(errorType.String(), "*models.ErrProcessRefund", "Type does not match *models.ErrProcessRefund")
53 | assert.Empty(order.OrderID)
54 | }
55 | })
56 | }
57 |
58 | func parseOrder(filename string) models.Order {
59 | inputFile, err := os.Open(filename)
60 | if err != nil {
61 | println("opening input file", err.Error())
62 | }
63 |
64 | defer inputFile.Close()
65 |
66 | jsonParser := json.NewDecoder(inputFile)
67 |
68 | o := models.Order{}
69 | if err = jsonParser.Decode(&o); err != nil {
70 | println("parsing input file", err.Error())
71 | }
72 |
73 | return o
74 | }
75 |
--------------------------------------------------------------------------------
/inventory-reserve/Makefile:
--------------------------------------------------------------------------------
1 | .PHONY: build-ReserveInventoryFunction
2 |
3 | build-ReserveInventoryFunction:
4 | GOOS=linux go build -o bootstrap
5 | cp ./bootstrap $(ARTIFACTS_DIR)/.
--------------------------------------------------------------------------------
/inventory-reserve/go.mod:
--------------------------------------------------------------------------------
1 | module aws-step-functions-long-lived-transactions/inventory-reserve
2 |
3 | go 1.16
4 |
5 | require (
6 | aws-step-functions-long-lived-transactions/models v0.0.0-00010101000000-000000000000
7 | github.com/andybalholm/brotli v1.0.3 // indirect
8 | github.com/aws/aws-lambda-go v1.24.0
9 | github.com/aws/aws-sdk-go v1.38.70
10 | github.com/aws/aws-xray-sdk-go v1.5.0
11 | github.com/klauspost/compress v1.13.1 // indirect
12 | github.com/stretchr/testify v1.6.1
13 | github.com/urfave/cli v1.22.1 // indirect
14 | github.com/valyala/fasthttp v1.28.0 // indirect
15 | golang.org/x/net v0.0.0-20210614182718-04defd469f4e // indirect
16 | golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c // indirect
17 | google.golang.org/genproto v0.0.0-20210630183607-d20f26d13c79 // indirect
18 | google.golang.org/grpc v1.39.0 // indirect
19 | )
20 |
21 | replace aws-step-functions-long-lived-transactions/models => ../models
22 |
--------------------------------------------------------------------------------
/inventory-reserve/go.sum:
--------------------------------------------------------------------------------
1 | cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
2 | cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
3 | dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
4 | github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
5 | github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
6 | github.com/DATA-DOG/go-sqlmock v1.2.0 h1:fQIJWMKY5xsIwZLZTqNYBbJyDfS+P2lyuZAyx9fvWVI=
7 | github.com/DATA-DOG/go-sqlmock v1.2.0/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM=
8 | github.com/DATA-DOG/go-sqlmock v1.4.1/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM=
9 | github.com/andybalholm/brotli v1.0.1/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y=
10 | github.com/andybalholm/brotli v1.0.2/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y=
11 | github.com/andybalholm/brotli v1.0.3 h1:fpcw+r1N1h0Poc1F/pHbW40cUm/lMEQslZtCkBQ0UnM=
12 | github.com/andybalholm/brotli v1.0.3/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
13 | github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
14 | github.com/aws/aws-lambda-go v1.13.2 h1:8lYuRVn6rESoUNZXdbCmtGB4bBk4vcVYojiHjE4mMrM=
15 | github.com/aws/aws-lambda-go v1.13.2/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU=
16 | github.com/aws/aws-lambda-go v1.24.0 h1:bOMerM175hLqHLdF1Nonfv1NA20nTIatuC0HK8eMoYg=
17 | github.com/aws/aws-lambda-go v1.24.0/go.mod h1:jJmlefzPfGnckuHdXX7/80O3BvUUi12XOkbv4w9SGLU=
18 | github.com/aws/aws-sdk-go v1.17.12/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
19 | github.com/aws/aws-sdk-go v1.25.26 h1:hMrxW3feteaGcP32oKaFdCQsCEWYf9zF12g73C0AcbI=
20 | github.com/aws/aws-sdk-go v1.25.26/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
21 | github.com/aws/aws-sdk-go v1.38.70 h1:EGHVUQzHIxQDF9LwQU22yE9bJd1HuBAWpJYSEnxnnhc=
22 | github.com/aws/aws-sdk-go v1.38.70/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro=
23 | github.com/aws/aws-xray-sdk-go v1.0.0-rc.14 h1:cxRNHoaVNiGhCddLe7A20nVFJsoWhs1jADm/1M97Ytw=
24 | github.com/aws/aws-xray-sdk-go v1.0.0-rc.14/go.mod h1:NCf+n91lACeo8klrI7RsKqDaAEXt321d/cfaJk4YuDM=
25 | github.com/aws/aws-xray-sdk-go v1.5.0 h1:/5uJ14/opeVzPGULnv3lYpqy8d47LKCxdm60m11dOVI=
26 | github.com/aws/aws-xray-sdk-go v1.5.0/go.mod h1:Ig1ouBiDz+jmMiufD7HHNFN+7ijGPbY53UZRir7Cu7Y=
27 | github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
28 | github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
29 | github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
30 | github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
31 | github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
32 | github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
33 | github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
34 | github.com/davecgh/go-spew v0.0.0-20160907170601-6d212800a42e/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
35 | github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
36 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
37 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
38 | github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
39 | github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
40 | github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
41 | github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
42 | github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
43 | github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ=
44 | github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
45 | github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
46 | github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
47 | github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
48 | github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
49 | github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
50 | github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw=
51 | github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
52 | github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
53 | github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
54 | github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
55 | github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
56 | github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
57 | github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
58 | github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
59 | github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
60 | github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
61 | github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
62 | github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
63 | github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
64 | github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
65 | github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
66 | github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
67 | github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
68 | github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
69 | github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
70 | github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
71 | github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
72 | github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
73 | github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
74 | github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
75 | github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
76 | github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
77 | github.com/grpc-ecosystem/go-grpc-middleware v1.2.2/go.mod h1:EaizFBKfUKtMIF5iaDEhniwNedqGo9FuLFzppDr3uwI=
78 | github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
79 | github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM=
80 | github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
81 | github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
82 | github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
83 | github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
84 | github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
85 | github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
86 | github.com/klauspost/compress v1.11.8/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
87 | github.com/klauspost/compress v1.12.2/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg=
88 | github.com/klauspost/compress v1.13.1 h1:wXr2uRxZTJXHLly6qhJabee5JqIhTRoLBhDOA74hDEQ=
89 | github.com/klauspost/compress v1.13.1/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg=
90 | github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
91 | github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
92 | github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
93 | github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
94 | github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
95 | github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
96 | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
97 | github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
98 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
99 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
100 | github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
101 | github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
102 | github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
103 | github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
104 | github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
105 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
106 | github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
107 | github.com/stretchr/testify v1.1.4/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
108 | github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
109 | github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
110 | github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
111 | github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
112 | github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
113 | github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
114 | github.com/urfave/cli/v2 v2.2.0/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ=
115 | github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
116 | github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
117 | github.com/valyala/fasthttp v1.24.0/go.mod h1:0mw2RjXGOzxf4NL2jni3gUQ7LfjjUSiG5sskOUUSEpU=
118 | github.com/valyala/fasthttp v1.28.0 h1:ruVmTmZaBR5i67NqnjvvH5gEv0zwHfWtbjoyW98iho4=
119 | github.com/valyala/fasthttp v1.28.0/go.mod h1:cmWIqlu99AO/RKcp1HWaViTqc57FswJOfYYdPJBl8BA=
120 | github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio=
121 | github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc=
122 | github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
123 | go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
124 | go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
125 | go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
126 | go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
127 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
128 | golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
129 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
130 | golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
131 | golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
132 | golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
133 | golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
134 | golang.org/x/exp v0.0.0-20200331195152-e8c3332aa8e5/go.mod h1:4M0jN8W1tt0AVLNr8HDosyJCDCDuyL9N9+3m7wDWgKw=
135 | golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
136 | golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
137 | golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
138 | golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
139 | golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
140 | golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
141 | golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
142 | golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
143 | golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
144 | golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
145 | golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
146 | golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
147 | golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
148 | golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
149 | golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
150 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
151 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
152 | golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553 h1:efeOvDhwQ29Dj3SdAV/MJf8oukgn+8D8WgaCaRMchF8=
153 | golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
154 | golang.org/x/net v0.0.0-20200421231249-e086a090c8fd/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
155 | golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
156 | golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
157 | golang.org/x/net v0.0.0-20210226101413-39120d07d75e/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
158 | golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
159 | golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
160 | golang.org/x/net v0.0.0-20210510120150-4163338589ed/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
161 | golang.org/x/net v0.0.0-20210614182718-04defd469f4e h1:XpT3nA5TvE525Ne3hInMh6+GETgn27Zfm9dxsThnX2Q=
162 | golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
163 | golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
164 | golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
165 | golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
166 | golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
167 | golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
168 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
169 | golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
170 | golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
171 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
172 | golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
173 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
174 | golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
175 | golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
176 | golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
177 | golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
178 | golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
179 | golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
180 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
181 | golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
182 | golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
183 | golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
184 | golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
185 | golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
186 | golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c h1:F1jZWGFhYfh0Ci55sIpILtKKK8p3i2/krTr0H1rg74I=
187 | golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
188 | golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
189 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
190 | golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
191 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
192 | golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
193 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
194 | golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
195 | golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
196 | golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
197 | golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
198 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
199 | golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
200 | golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
201 | golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
202 | golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
203 | golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
204 | golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
205 | golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
206 | golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
207 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
208 | golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
209 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
210 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
211 | google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
212 | google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
213 | google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
214 | google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
215 | google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
216 | google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
217 | google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
218 | google.golang.org/genproto v0.0.0-20210114201628-6edceaf6022f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
219 | google.golang.org/genproto v0.0.0-20210630183607-d20f26d13c79 h1:s1jFTXJryg4a1mew7xv03VZD8N9XjxFhk1o4Js4WvPQ=
220 | google.golang.org/genproto v0.0.0-20210630183607-d20f26d13c79/go.mod h1:yiaVoXHpRzHGyxV3o4DktVWY4mSUErTKaeEOq6C3t3U=
221 | google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
222 | google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
223 | google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
224 | google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
225 | google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
226 | google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
227 | google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
228 | google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
229 | google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
230 | google.golang.org/grpc v1.39.0 h1:Klz8I9kdtkIN6EpHHUOMLCYhTn/2WAe5a0s1hcBkdTI=
231 | google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE=
232 | google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
233 | google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
234 | google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
235 | google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
236 | google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
237 | google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
238 | google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
239 | google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
240 | google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
241 | google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
242 | google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
243 | google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
244 | google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ=
245 | google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
246 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
247 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
248 | gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
249 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
250 | gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
251 | gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
252 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
253 | gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
254 | honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
255 | honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
256 |
--------------------------------------------------------------------------------
/inventory-reserve/main.go:
--------------------------------------------------------------------------------
1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2 | // SPDX-License-Identifier: MIT-0
3 | package main
4 |
5 | import (
6 | "context"
7 | "fmt"
8 | "log"
9 | "os"
10 |
11 | "aws-step-functions-long-lived-transactions/models" // local
12 |
13 | "github.com/aws/aws-lambda-go/lambda"
14 | "github.com/aws/aws-sdk-go/aws"
15 | "github.com/aws/aws-sdk-go/aws/session"
16 | "github.com/aws/aws-sdk-go/service/dynamodb"
17 | "github.com/aws/aws-sdk-go/service/dynamodb/dynamodbattribute"
18 | "github.com/aws/aws-xray-sdk-go/xray"
19 | )
20 |
21 | var dynamoDB *dynamodb.DynamoDB
22 |
23 | func init() {
24 |
25 | // Create DynamoDB client
26 | var awscfg = &aws.Config{
27 | Region: aws.String(os.Getenv("AWS_REGION")),
28 | }
29 | var sess = session.Must(session.NewSession(awscfg))
30 | dynamoDB = dynamodb.New(sess)
31 |
32 | // AWS X-Ray for AWS SDK trace
33 | xray.AWS(dynamoDB.Client)
34 |
35 | log.SetPrefix("TRACE: ")
36 | log.SetFlags(log.Ldate | log.Ltime)
37 |
38 | }
39 |
40 | func handler(ctx context.Context, ord models.Order) (models.Order, error) {
41 |
42 | log.Printf("[%s] - processing inventory reservation", ord.OrderID)
43 |
44 | var newInvTrans = models.Inventory{
45 | OrderID: ord.OrderID,
46 | OrderItems: ord.ItemIds(),
47 | }
48 |
49 | // reserve the items in the inventory
50 | newInvTrans.Reserve()
51 |
52 | // Annotate saga with inventory transaction id
53 | ord.Inventory = newInvTrans
54 |
55 | // Save the reservation
56 | err := saveInventory(ctx, newInvTrans)
57 | if err != nil {
58 | log.Printf("[%s] - error! %s", ord.OrderID, err.Error())
59 | return models.Order{}, models.NewErrReserveInventory(err.Error())
60 | }
61 |
62 | // testing scenario
63 | if ord.OrderID[0:1] == "3" {
64 | return ord, models.NewErrReserveInventory("Unable to update newInvTrans for order " + ord.OrderID)
65 | }
66 |
67 | log.Printf("[%s] - reservation processed", ord.OrderID)
68 |
69 | return ord, nil
70 | }
71 |
72 | func saveInventory(ctx context.Context, newInvTrans models.Inventory) error {
73 |
74 | marshalledOrder, err := dynamodbattribute.MarshalMap(newInvTrans)
75 | if err != nil {
76 | return fmt.Errorf("failed to DynamoDB marshal Inventory, %v", err)
77 | }
78 |
79 | _, err = dynamoDB.PutItemWithContext(ctx, &dynamodb.PutItemInput{
80 | TableName: aws.String(os.Getenv("TABLE_NAME")),
81 | Item: marshalledOrder,
82 | })
83 | if err != nil {
84 | return fmt.Errorf("failed to put record to DynamoDB, %v", err)
85 | }
86 |
87 | return nil
88 | }
89 |
90 | func main() {
91 | lambda.Start(handler)
92 | }
93 |
--------------------------------------------------------------------------------
/inventory-reserve/main_test.go:
--------------------------------------------------------------------------------
1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2 | // SPDX-License-Identifier: MIT-0
3 | package main
4 |
5 | import (
6 | "encoding/json"
7 | "fmt"
8 | "os"
9 | "reflect"
10 | "testing"
11 |
12 | "aws-step-functions-long-lived-transactions/models"
13 |
14 | "github.com/stretchr/testify/assert"
15 | )
16 |
17 | // Test Orders
18 | var scenarioErrInventoryUpdate = "../testdata/scenario-5.json"
19 | var scenarioSuccessfulOrder = "../testdata/scenario-7.json"
20 |
21 | func TestHandler(t *testing.T) {
22 | assert := assert.New(t)
23 |
24 | t.Run("ProcessPayment", func(t *testing.T) {
25 |
26 | o := parseOrder(scenarioSuccessfulOrder)
27 |
28 | order, err := handler(nil, o)
29 | if err != nil {
30 | t.Fatal(err)
31 | }
32 |
33 | assert.NotEmpty(order.Inventory.TransactionID, "Inventory TransactionID must not be empty")
34 |
35 | })
36 | }
37 |
38 | func TestErrorIsOfTypeErrInventoryUpdate(t *testing.T) {
39 | assert := assert.New(t)
40 | t.Run("ProcessPaymentErr", func(t *testing.T) {
41 |
42 | input := parseOrder(scenarioErrInventoryUpdate)
43 |
44 | order, err := handler(nil, input)
45 | if err != nil {
46 | fmt.Print(err)
47 | }
48 |
49 | if assert.Error(err) {
50 | errorType := reflect.TypeOf(err)
51 | assert.Equal(errorType.String(), "*models.ErrReserveInventory", "Type does not match *models.ErrReserveInventory")
52 | assert.Empty(order.OrderID)
53 | }
54 | })
55 | }
56 |
57 | func parseOrder(filename string) models.Order {
58 | inputFile, err := os.Open(filename)
59 | if err != nil {
60 | println("opening input file", err.Error())
61 | }
62 |
63 | defer inputFile.Close()
64 |
65 | jsonParser := json.NewDecoder(inputFile)
66 |
67 | order := models.Order{}
68 | if err = jsonParser.Decode(&order); err != nil {
69 | println("parsing input file", err.Error())
70 | }
71 |
72 | return o
73 | }
74 |
--------------------------------------------------------------------------------
/models/go.mod:
--------------------------------------------------------------------------------
1 | module aws-step-functions-long-lived-transactions/models
2 |
3 | go 1.16
4 |
5 | require github.com/gofrs/uuid v4.0.0+incompatible
6 |
--------------------------------------------------------------------------------
/models/go.sum:
--------------------------------------------------------------------------------
1 | github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw=
2 | github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
3 |
--------------------------------------------------------------------------------
/models/inventory.go:
--------------------------------------------------------------------------------
1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2 | // SPDX-License-Identifier: MIT-0
3 | package models
4 |
5 | import (
6 | "time"
7 |
8 | "github.com/gofrs/uuid"
9 | )
10 |
11 | // Inventory represents the transaction on inventory
12 | type Inventory struct {
13 | TransactionID string `json:"transaction_id,omitempty"`
14 | TransactionDate string `json:"transaction_date,omitempty"`
15 | OrderID string `json:"order_id,omitempty"`
16 | OrderItems []string `json:"items,omitempty"`
17 | TransactionType string `json:"transaction_type,omitempty"`
18 | }
19 |
20 | // Reserve method removes items from the inventory
21 | func (i *Inventory) Reserve() {
22 | i.TransactionID = uuid.Must(uuid.NewV4()).String()
23 | i.TransactionDate = time.Now().Format(time.RFC3339)
24 | i.TransactionType = "Reserve"
25 | }
26 |
27 | // Release method makes items from the inventory available
28 | func (i *Inventory) Release() {
29 | i.TransactionID = uuid.Must(uuid.NewV4()).String()
30 | i.TransactionDate = time.Now().Format(time.RFC3339)
31 | i.TransactionType = "Release"
32 | }
33 |
34 | /* //////////////////////////
35 | // CUSTOM ERRORS
36 | */ //////////////////////////
37 |
38 | // ErrReserveInventory represents a inventory update error
39 | type ErrReserveInventory struct {
40 | message string
41 | }
42 |
43 | // NewErrReserveInventory constructor
44 | func NewErrReserveInventory(message string) *ErrReserveInventory {
45 | return &ErrReserveInventory{
46 | message: message,
47 | }
48 | }
49 |
50 | func (e *ErrReserveInventory) Error() string {
51 | return e.message
52 | }
53 |
54 | // ErrReleaseInventory represents a inventory update reversal error
55 | type ErrReleaseInventory struct {
56 | message string
57 | }
58 |
59 | // NewErrReleaseInventory constructor
60 | func NewErrReleaseInventory(message string) *ErrReleaseInventory {
61 | return &ErrReleaseInventory{
62 | message: message,
63 | }
64 | }
65 |
66 | func (e *ErrReleaseInventory) Error() string {
67 | return e.message
68 | }
69 |
--------------------------------------------------------------------------------
/models/order.go:
--------------------------------------------------------------------------------
1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2 | // SPDX-License-Identifier: MIT-0
3 | package models
4 |
5 | import (
6 | "time"
7 | )
8 |
9 | // Order represents a customer order
10 | type Order struct {
11 | OrderID string `json:"order_id,omitempty"`
12 | OrderDate time.Time `json:"order_date,omitempty"`
13 | CustomerID string `json:"customer_id,omitempty"`
14 | OrderStatus string `json:"order_status,omitempty"`
15 | Items []Item `json:"items,omitempty"`
16 | Payment Payment `json:"payment,omitempty"`
17 | Inventory Inventory `json:"inventory,omitempty"`
18 | }
19 |
20 | // Item represents an item in the cart
21 | type Item struct {
22 | ItemID string `json:"item_id,omitempty"`
23 | Qty float64 `json:"qty,omitempty"`
24 | Description string `json:"description,omitempty"`
25 | UnitPrice float64 `json:"unit_price,omitempty"`
26 | }
27 |
28 | // Total returns the total ammount of the order
29 | func (o Order) Total() float64 {
30 | var total = 0.0
31 | for i := 0; i <= len(o.Items)-1; i++ {
32 |
33 | item := o.Items[i]
34 | total += item.UnitPrice * item.Qty
35 | }
36 | return total
37 | }
38 |
39 | // ItemIds returns a slice of Ids or Items in the order
40 | func (o Order) ItemIds() []string {
41 |
42 | var orderItemIds []string
43 |
44 | for i := 0; i <= len(o.Items)-1; i++ {
45 |
46 | item := o.Items[i]
47 |
48 | orderItemIds = append(orderItemIds, item.ItemID)
49 |
50 | }
51 |
52 | return orderItemIds
53 | }
54 |
55 | /* //////////////////////////
56 | // CUSTOM ERRORS
57 | */ //////////////////////////
58 |
59 | // ErrProcessOrder represents a process order error
60 | type ErrProcessOrder struct {
61 | message string
62 | }
63 |
64 | // NewErrProcessOrder constructor
65 | func NewErrProcessOrder(message string) *ErrProcessOrder {
66 | return &ErrProcessOrder{
67 | message: message,
68 | }
69 | }
70 |
71 | func (e *ErrProcessOrder) Error() string {
72 | return e.message
73 | }
74 |
75 | // ErrUpdateOrderStatus represents a process order error
76 | type ErrUpdateOrderStatus struct {
77 | message string
78 | }
79 |
80 | // NewErrUpdateOrderStatus constructor
81 | func NewErrUpdateOrderStatus(message string) *ErrUpdateOrderStatus {
82 | return &ErrUpdateOrderStatus{
83 | message: message,
84 | }
85 | }
86 |
87 | func (e *ErrUpdateOrderStatus) Error() string {
88 | return e.message
89 | }
90 |
--------------------------------------------------------------------------------
/models/payment.go:
--------------------------------------------------------------------------------
1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2 | // SPDX-License-Identifier: MIT-0
3 | package models
4 |
5 | import (
6 | "time"
7 |
8 | "github.com/gofrs/uuid"
9 | )
10 |
11 | // Payment represents a customer credit card payment
12 | type Payment struct {
13 | MerchantID string `json:"merchant_id,omitempty"`
14 | PaymentAmount float64 `json:"payment_amount,omitempty"`
15 | TransactionID string `json:"transaction_id,omitempty"`
16 | TransactionDate string `json:"transaction_date,omitempty"`
17 | OrderID string `json:"order_id,omitempty"`
18 | PaymentType string `json:"payment_type,omitempty"`
19 | }
20 |
21 | // Pay customer order payment
22 | func (p *Payment) Pay() {
23 | // process payment for customer order
24 | p.TransactionID = uuid.Must(uuid.NewV4()).String()
25 | p.TransactionDate = time.Now().Format(time.RFC3339)
26 | p.PaymentType = "Debit"
27 |
28 | }
29 |
30 | // Refund customer order
31 | func (p *Payment) Refund() {
32 | p.TransactionID = uuid.Must(uuid.NewV4()).String()
33 | p.TransactionDate = time.Now().Format(time.RFC3339)
34 | p.PaymentAmount = -(p.PaymentAmount)
35 | p.PaymentType = "Credit"
36 | }
37 |
38 | /* //////////////////////////
39 | // CUSTOM ERRORS
40 | */ //////////////////////////
41 |
42 | // ErrProcessPayment represents a process payment error
43 | type ErrProcessPayment struct {
44 | message string
45 | }
46 |
47 | // NewErrProcessPayment constructor
48 | func NewErrProcessPayment(message string) *ErrProcessPayment {
49 | return &ErrProcessPayment{
50 | message: message,
51 | }
52 | }
53 | func (e *ErrProcessPayment) Error() string {
54 | return e.message
55 | }
56 |
57 | // ErrProcessRefund represents a process payment refund error
58 | type ErrProcessRefund struct {
59 | message string
60 | }
61 |
62 | // NewErrProcessRefund constructor
63 | func NewErrProcessRefund(message string) *ErrProcessRefund {
64 | return &ErrProcessRefund{
65 | message: message,
66 | }
67 | }
68 | func (e *ErrProcessRefund) Error() string {
69 | return e.message
70 | }
71 |
--------------------------------------------------------------------------------
/order-new/Makefile:
--------------------------------------------------------------------------------
1 | .PHONY: build-NewOrderFunction
2 |
3 | build-NewOrderFunction:
4 | GOOS=linux go build -o bootstrap
5 | cp ./bootstrap $(ARTIFACTS_DIR)/.
--------------------------------------------------------------------------------
/order-new/go.mod:
--------------------------------------------------------------------------------
1 | module aws-step-functions-long-lived-transactions/order-new
2 |
3 | go 1.16
4 |
5 | require (
6 | aws-step-functions-long-lived-transactions/models v0.0.0-00010101000000-000000000000
7 | github.com/andybalholm/brotli v1.0.3 // indirect
8 | github.com/aws/aws-lambda-go v1.24.0
9 | github.com/aws/aws-sdk-go v1.38.70
10 | github.com/aws/aws-xray-sdk-go v1.5.0
11 | github.com/klauspost/compress v1.13.1 // indirect
12 | github.com/stretchr/testify v1.7.0
13 | github.com/valyala/fasthttp v1.28.0 // indirect
14 | golang.org/x/net v0.0.0-20210614182718-04defd469f4e // indirect
15 | golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c // indirect
16 | google.golang.org/genproto v0.0.0-20210630183607-d20f26d13c79 // indirect
17 | google.golang.org/grpc v1.39.0 // indirect
18 | )
19 |
20 | replace aws-step-functions-long-lived-transactions/models => ../models
21 |
--------------------------------------------------------------------------------
/order-new/go.sum:
--------------------------------------------------------------------------------
1 | cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
2 | cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
3 | dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
4 | github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
5 | github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
6 | github.com/DATA-DOG/go-sqlmock v1.4.1 h1:ThlnYciV1iM/V0OSF/dtkqWb6xo5qITT1TJBG1MRDJM=
7 | github.com/DATA-DOG/go-sqlmock v1.4.1/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM=
8 | github.com/andybalholm/brotli v1.0.1 h1:KqhlKozYbRtJvsPrrEeXcO+N2l6NYT5A2QAFmSULpEc=
9 | github.com/andybalholm/brotli v1.0.1/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y=
10 | github.com/andybalholm/brotli v1.0.2/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y=
11 | github.com/andybalholm/brotli v1.0.3 h1:fpcw+r1N1h0Poc1F/pHbW40cUm/lMEQslZtCkBQ0UnM=
12 | github.com/andybalholm/brotli v1.0.3/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
13 | github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
14 | github.com/aws/aws-lambda-go v1.24.0 h1:bOMerM175hLqHLdF1Nonfv1NA20nTIatuC0HK8eMoYg=
15 | github.com/aws/aws-lambda-go v1.24.0/go.mod h1:jJmlefzPfGnckuHdXX7/80O3BvUUi12XOkbv4w9SGLU=
16 | github.com/aws/aws-sdk-go v1.17.12/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
17 | github.com/aws/aws-sdk-go v1.38.69 h1:V489lmrdkIQSfF6OAGZZ1Cavcm7eczCm2JcGvX+yHRg=
18 | github.com/aws/aws-sdk-go v1.38.69/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro=
19 | github.com/aws/aws-sdk-go v1.38.70 h1:EGHVUQzHIxQDF9LwQU22yE9bJd1HuBAWpJYSEnxnnhc=
20 | github.com/aws/aws-sdk-go v1.38.70/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro=
21 | github.com/aws/aws-xray-sdk-go v1.5.0 h1:/5uJ14/opeVzPGULnv3lYpqy8d47LKCxdm60m11dOVI=
22 | github.com/aws/aws-xray-sdk-go v1.5.0/go.mod h1:Ig1ouBiDz+jmMiufD7HHNFN+7ijGPbY53UZRir7Cu7Y=
23 | github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
24 | github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
25 | github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
26 | github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
27 | github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
28 | github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
29 | github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
30 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
31 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
32 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
33 | github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
34 | github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
35 | github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
36 | github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
37 | github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
38 | github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ=
39 | github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
40 | github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
41 | github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
42 | github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
43 | github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
44 | github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
45 | github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw=
46 | github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
47 | github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
48 | github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
49 | github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
50 | github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
51 | github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
52 | github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
53 | github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
54 | github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
55 | github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
56 | github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
57 | github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
58 | github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
59 | github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
60 | github.com/golang/protobuf v1.4.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM=
61 | github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
62 | github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
63 | github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
64 | github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
65 | github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
66 | github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
67 | github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
68 | github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
69 | github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
70 | github.com/google/go-cmp v0.5.0 h1:/QaMHBdZ26BB3SSst0Iwl10Epc+xhTquomWX0oZEB6w=
71 | github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
72 | github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
73 | github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
74 | github.com/grpc-ecosystem/go-grpc-middleware v1.2.2 h1:FlFbCRLd5Jr4iYXZufAvgWN6Ao0JrI5chLINnUXDDr0=
75 | github.com/grpc-ecosystem/go-grpc-middleware v1.2.2/go.mod h1:EaizFBKfUKtMIF5iaDEhniwNedqGo9FuLFzppDr3uwI=
76 | github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
77 | github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
78 | github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
79 | github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
80 | github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8=
81 | github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
82 | github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
83 | github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
84 | github.com/klauspost/compress v1.11.8 h1:difgzQsp5mdAz9v8lm3P/I+EpDKMU/6uTMw1y1FObuo=
85 | github.com/klauspost/compress v1.11.8/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
86 | github.com/klauspost/compress v1.12.2/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg=
87 | github.com/klauspost/compress v1.13.1 h1:wXr2uRxZTJXHLly6qhJabee5JqIhTRoLBhDOA74hDEQ=
88 | github.com/klauspost/compress v1.13.1/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg=
89 | github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
90 | github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
91 | github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
92 | github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
93 | github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
94 | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
95 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
96 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
97 | github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
98 | github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
99 | github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
100 | github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
101 | github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
102 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
103 | github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
104 | github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
105 | github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
106 | github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
107 | github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
108 | github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
109 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
110 | github.com/urfave/cli/v2 v2.2.0/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ=
111 | github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
112 | github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
113 | github.com/valyala/fasthttp v1.24.0 h1:AAiG4oLDUArTb7rYf9oO2bkGooOqCaUF6a2u8asBP3I=
114 | github.com/valyala/fasthttp v1.24.0/go.mod h1:0mw2RjXGOzxf4NL2jni3gUQ7LfjjUSiG5sskOUUSEpU=
115 | github.com/valyala/fasthttp v1.28.0 h1:ruVmTmZaBR5i67NqnjvvH5gEv0zwHfWtbjoyW98iho4=
116 | github.com/valyala/fasthttp v1.28.0/go.mod h1:cmWIqlu99AO/RKcp1HWaViTqc57FswJOfYYdPJBl8BA=
117 | github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio=
118 | github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc=
119 | github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
120 | go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
121 | go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
122 | go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
123 | go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
124 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
125 | golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
126 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
127 | golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
128 | golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
129 | golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
130 | golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
131 | golang.org/x/exp v0.0.0-20200331195152-e8c3332aa8e5/go.mod h1:4M0jN8W1tt0AVLNr8HDosyJCDCDuyL9N9+3m7wDWgKw=
132 | golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
133 | golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
134 | golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
135 | golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
136 | golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
137 | golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
138 | golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
139 | golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
140 | golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
141 | golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
142 | golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
143 | golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
144 | golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
145 | golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
146 | golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
147 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
148 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
149 | golang.org/x/net v0.0.0-20200421231249-e086a090c8fd/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
150 | golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
151 | golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
152 | golang.org/x/net v0.0.0-20210226101413-39120d07d75e/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
153 | golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
154 | golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
155 | golang.org/x/net v0.0.0-20210510120150-4163338589ed/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
156 | golang.org/x/net v0.0.0-20210614182718-04defd469f4e h1:XpT3nA5TvE525Ne3hInMh6+GETgn27Zfm9dxsThnX2Q=
157 | golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
158 | golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
159 | golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
160 | golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
161 | golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
162 | golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
163 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
164 | golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
165 | golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
166 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
167 | golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
168 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
169 | golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
170 | golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
171 | golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
172 | golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
173 | golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
174 | golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
175 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
176 | golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
177 | golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
178 | golang.org/x/sys v0.0.0-20210423082822-04245dca01da h1:b3NXsE2LusjYGGjL5bxEVZZORm/YEFFrWFjR8eFrw/c=
179 | golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
180 | golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
181 | golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
182 | golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c h1:F1jZWGFhYfh0Ci55sIpILtKKK8p3i2/krTr0H1rg74I=
183 | golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
184 | golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
185 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
186 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
187 | golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
188 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
189 | golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
190 | golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
191 | golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
192 | golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
193 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
194 | golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
195 | golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
196 | golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
197 | golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
198 | golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
199 | golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
200 | golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
201 | golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
202 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
203 | golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
204 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
205 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
206 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
207 | google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
208 | google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
209 | google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
210 | google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
211 | google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
212 | google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
213 | google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
214 | google.golang.org/genproto v0.0.0-20210114201628-6edceaf6022f h1:izedQ6yVIc5mZsRuXzmSreCOlzI0lCU1HpG8yEdMiKw=
215 | google.golang.org/genproto v0.0.0-20210114201628-6edceaf6022f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
216 | google.golang.org/genproto v0.0.0-20210630183607-d20f26d13c79 h1:s1jFTXJryg4a1mew7xv03VZD8N9XjxFhk1o4Js4WvPQ=
217 | google.golang.org/genproto v0.0.0-20210630183607-d20f26d13c79/go.mod h1:yiaVoXHpRzHGyxV3o4DktVWY4mSUErTKaeEOq6C3t3U=
218 | google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
219 | google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
220 | google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
221 | google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
222 | google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
223 | google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
224 | google.golang.org/grpc v1.35.0 h1:TwIQcH3es+MojMVojxxfQ3l3OF2KzlRxML2xZq0kRo8=
225 | google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
226 | google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
227 | google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
228 | google.golang.org/grpc v1.39.0 h1:Klz8I9kdtkIN6EpHHUOMLCYhTn/2WAe5a0s1hcBkdTI=
229 | google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE=
230 | google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
231 | google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
232 | google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
233 | google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
234 | google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
235 | google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
236 | google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
237 | google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
238 | google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
239 | google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c=
240 | google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
241 | google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
242 | google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
243 | google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ=
244 | google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
245 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
246 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
247 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
248 | gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
249 | gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
250 | gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
251 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
252 | gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 h1:tQIYjPdBoyREyB9XMu+nnTclpTYkz2zFM+lzLJFO4gQ=
253 | gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
254 | honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
255 | honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
256 |
--------------------------------------------------------------------------------
/order-new/main.go:
--------------------------------------------------------------------------------
1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2 | // SPDX-License-Identifier: MIT-0
3 | package main
4 |
5 | import (
6 | "context"
7 | "fmt"
8 | "log"
9 | "os"
10 |
11 | "aws-step-functions-long-lived-transactions/models"
12 |
13 | "github.com/aws/aws-lambda-go/lambda"
14 | "github.com/aws/aws-sdk-go/aws"
15 | "github.com/aws/aws-sdk-go/aws/session"
16 | "github.com/aws/aws-sdk-go/service/dynamodb"
17 | "github.com/aws/aws-sdk-go/service/dynamodb/dynamodbattribute"
18 | "github.com/aws/aws-xray-sdk-go/xray"
19 | )
20 |
21 | var dynamoDB *dynamodb.DynamoDB
22 |
23 | func init() {
24 |
25 | // Create DynamoDB client
26 | var awscfg = &aws.Config{
27 | Region: aws.String(os.Getenv("AWS_REGION")),
28 | }
29 | var sess = session.Must(session.NewSession(awscfg))
30 | dynamoDB = dynamodb.New(sess)
31 |
32 | // AWS X-Ray for AWS SDK trace
33 | xray.AWS(dynamoDB.Client)
34 |
35 | log.SetPrefix("TRACE: ")
36 | log.SetFlags(log.Ldate | log.Ltime)
37 |
38 | }
39 |
40 | // handler for the Lambda function
41 | func handler(ctx context.Context, ord models.Order) (models.Order, error) {
42 |
43 | log.Printf("[%s] - received new order", ord.OrderID)
44 |
45 | // persist the order data. Set order status to new
46 | ord.OrderStatus = "New"
47 |
48 | err := saveOrder(ctx, ord)
49 | if err != nil {
50 | log.Printf("[%s] - error! %s", ord.OrderID, err.Error())
51 | return models.Order{}, models.NewErrProcessOrder(err.Error())
52 | }
53 |
54 | // testing scenario
55 | if ord.OrderID[0:1] == "1" {
56 | return models.Order{}, models.NewErrProcessOrder("Unable to process order " + ord.OrderID)
57 | }
58 |
59 | log.Printf("[%s] - order status set to new", ord.OrderID)
60 |
61 | return ord, nil
62 | }
63 |
64 | func saveOrder(ctx context.Context, order models.Order) error {
65 |
66 | marshalledOrder, err := dynamodbattribute.MarshalMap(order)
67 | if err != nil {
68 | return fmt.Errorf("failed to DynamoDB marshal Order, %v", err)
69 | }
70 |
71 | _, err = dynamoDB.PutItemWithContext(ctx, &dynamodb.PutItemInput{
72 | TableName: aws.String(os.Getenv("TABLE_NAME")),
73 | Item: marshalledOrder,
74 | })
75 | if err != nil {
76 | return fmt.Errorf("failed to put record to DynamoDB, %v", err)
77 | }
78 | return nil
79 | }
80 |
81 | func main() {
82 | lambda.Start(handler)
83 | }
84 |
--------------------------------------------------------------------------------
/order-new/main_test.go:
--------------------------------------------------------------------------------
1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2 | // SPDX-License-Identifier: MIT-0
3 | package main
4 |
5 | import (
6 | "encoding/json"
7 | "fmt"
8 | "os"
9 | "reflect"
10 | "testing"
11 |
12 | "aws-step-functions-long-lived-transactions/models"
13 |
14 | "github.com/stretchr/testify/assert"
15 | )
16 |
17 | var scenarioErrProcessOrder = "../testdata/scenario-1.json"
18 | var scenarioSuccessfulOrder = "../testdata/scenario-7.json"
19 |
20 | func TestHandler(t *testing.T) {
21 | assert := assert.New(t)
22 |
23 | t.Run("ProcessOrder", func(t *testing.T) {
24 |
25 | o := parseOrder(scenarioSuccessfulOrder)
26 |
27 | order, err := handler(nil, o)
28 | if err != nil {
29 | t.Fatal("Error failed to trigger with an invalid request")
30 | }
31 |
32 | assert.NotEmpty(order.OrderID, "OrderID must be empty")
33 | assert.NotEmpty(order.CustomerID, "CustomerID must not be empty")
34 | assert.True(order.Total() == 56.97, "OrderTotal does not equal expected value")
35 | assert.True(len(order.Items) == 3, "OrderItems should be contain 3 items ids")
36 |
37 | })
38 | }
39 |
40 | func TestErrorIsOfTypeErrProcessOrder(t *testing.T) {
41 | assert := assert.New(t)
42 |
43 | t.Run("OrderProcessErr", func(t *testing.T) {
44 |
45 | input := parseOrder(scenarioErrProcessOrder)
46 |
47 | order, err := handler(nil, input)
48 | if err != nil {
49 | fmt.Print(err)
50 | }
51 |
52 | assert.NotEmpty(order)
53 |
54 | if assert.Error(err) {
55 | errorType := reflect.TypeOf(err)
56 | assert.Equal(errorType.String(), "*models.ErrProcessOrder", "Type does not match *models.ErrProcessOrder")
57 | }
58 | })
59 | }
60 |
61 | func parseOrder(filename string) models.Order {
62 | inputFile, err := os.Open(filename)
63 | if err != nil {
64 | println("opening input file", err.Error())
65 | }
66 |
67 | defer inputFile.Close()
68 |
69 | jsonParser := json.NewDecoder(inputFile)
70 |
71 | o := models.Order{}
72 | if err = jsonParser.Decode(&o); err != nil {
73 | println("parsing input file", err.Error())
74 | }
75 |
76 | return o
77 | }
78 |
--------------------------------------------------------------------------------
/order-update/Makefile:
--------------------------------------------------------------------------------
1 | .PHONY: build-UpdateOrderFunction
2 |
3 | build-UpdateOrderFunction:
4 | GOOS=linux go build -o bootstrap
5 | cp ./bootstrap $(ARTIFACTS_DIR)/.
--------------------------------------------------------------------------------
/order-update/go.mod:
--------------------------------------------------------------------------------
1 | module aws-step-functions-long-lived-transactions/order-update
2 |
3 | go 1.16
4 |
5 | require (
6 | aws-step-functions-long-lived-transactions/models v0.0.0-00010101000000-000000000000
7 | github.com/andybalholm/brotli v1.0.3 // indirect
8 | github.com/aws/aws-lambda-go v1.24.0
9 | github.com/aws/aws-sdk-go v1.38.70
10 | github.com/aws/aws-xray-sdk-go v1.5.0
11 | github.com/klauspost/compress v1.13.1 // indirect
12 | github.com/stretchr/testify v1.7.0
13 | github.com/valyala/fasthttp v1.28.0 // indirect
14 | golang.org/x/net v0.0.0-20210614182718-04defd469f4e // indirect
15 | golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c // indirect
16 | google.golang.org/genproto v0.0.0-20210630183607-d20f26d13c79 // indirect
17 | google.golang.org/grpc v1.39.0 // indirect
18 | gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
19 | )
20 |
21 | replace aws-step-functions-long-lived-transactions/models => ../models
22 |
--------------------------------------------------------------------------------
/order-update/go.sum:
--------------------------------------------------------------------------------
1 | cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
2 | cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
3 | dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
4 | github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
5 | github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
6 | github.com/DATA-DOG/go-sqlmock v1.4.1 h1:ThlnYciV1iM/V0OSF/dtkqWb6xo5qITT1TJBG1MRDJM=
7 | github.com/DATA-DOG/go-sqlmock v1.4.1/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM=
8 | github.com/andybalholm/brotli v1.0.1/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y=
9 | github.com/andybalholm/brotli v1.0.2/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y=
10 | github.com/andybalholm/brotli v1.0.3 h1:fpcw+r1N1h0Poc1F/pHbW40cUm/lMEQslZtCkBQ0UnM=
11 | github.com/andybalholm/brotli v1.0.3/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
12 | github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
13 | github.com/aws/aws-lambda-go v1.24.0 h1:bOMerM175hLqHLdF1Nonfv1NA20nTIatuC0HK8eMoYg=
14 | github.com/aws/aws-lambda-go v1.24.0/go.mod h1:jJmlefzPfGnckuHdXX7/80O3BvUUi12XOkbv4w9SGLU=
15 | github.com/aws/aws-sdk-go v1.17.12/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
16 | github.com/aws/aws-sdk-go v1.38.70 h1:EGHVUQzHIxQDF9LwQU22yE9bJd1HuBAWpJYSEnxnnhc=
17 | github.com/aws/aws-sdk-go v1.38.70/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro=
18 | github.com/aws/aws-xray-sdk-go v1.5.0 h1:/5uJ14/opeVzPGULnv3lYpqy8d47LKCxdm60m11dOVI=
19 | github.com/aws/aws-xray-sdk-go v1.5.0/go.mod h1:Ig1ouBiDz+jmMiufD7HHNFN+7ijGPbY53UZRir7Cu7Y=
20 | github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
21 | github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
22 | github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
23 | github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
24 | github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
25 | github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
26 | github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
27 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
28 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
29 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
30 | github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
31 | github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
32 | github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
33 | github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
34 | github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
35 | github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ=
36 | github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
37 | github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
38 | github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
39 | github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
40 | github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
41 | github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
42 | github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw=
43 | github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
44 | github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
45 | github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
46 | github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
47 | github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
48 | github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
49 | github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
50 | github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
51 | github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
52 | github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
53 | github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
54 | github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
55 | github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
56 | github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
57 | github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
58 | github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
59 | github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
60 | github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
61 | github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
62 | github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
63 | github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
64 | github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
65 | github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
66 | github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
67 | github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
68 | github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
69 | github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
70 | github.com/grpc-ecosystem/go-grpc-middleware v1.2.2 h1:FlFbCRLd5Jr4iYXZufAvgWN6Ao0JrI5chLINnUXDDr0=
71 | github.com/grpc-ecosystem/go-grpc-middleware v1.2.2/go.mod h1:EaizFBKfUKtMIF5iaDEhniwNedqGo9FuLFzppDr3uwI=
72 | github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
73 | github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
74 | github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
75 | github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
76 | github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8=
77 | github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
78 | github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
79 | github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
80 | github.com/klauspost/compress v1.11.8/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
81 | github.com/klauspost/compress v1.12.2/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg=
82 | github.com/klauspost/compress v1.13.1 h1:wXr2uRxZTJXHLly6qhJabee5JqIhTRoLBhDOA74hDEQ=
83 | github.com/klauspost/compress v1.13.1/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg=
84 | github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
85 | github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
86 | github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
87 | github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
88 | github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
89 | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
90 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
91 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
92 | github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
93 | github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
94 | github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
95 | github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
96 | github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
97 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
98 | github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
99 | github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
100 | github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
101 | github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
102 | github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
103 | github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
104 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
105 | github.com/urfave/cli/v2 v2.2.0/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ=
106 | github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
107 | github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
108 | github.com/valyala/fasthttp v1.24.0/go.mod h1:0mw2RjXGOzxf4NL2jni3gUQ7LfjjUSiG5sskOUUSEpU=
109 | github.com/valyala/fasthttp v1.28.0 h1:ruVmTmZaBR5i67NqnjvvH5gEv0zwHfWtbjoyW98iho4=
110 | github.com/valyala/fasthttp v1.28.0/go.mod h1:cmWIqlu99AO/RKcp1HWaViTqc57FswJOfYYdPJBl8BA=
111 | github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio=
112 | github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc=
113 | github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
114 | go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
115 | go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
116 | go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
117 | go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
118 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
119 | golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
120 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
121 | golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
122 | golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
123 | golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
124 | golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
125 | golang.org/x/exp v0.0.0-20200331195152-e8c3332aa8e5/go.mod h1:4M0jN8W1tt0AVLNr8HDosyJCDCDuyL9N9+3m7wDWgKw=
126 | golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
127 | golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
128 | golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
129 | golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
130 | golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
131 | golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
132 | golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
133 | golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
134 | golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
135 | golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
136 | golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
137 | golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
138 | golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
139 | golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
140 | golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
141 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
142 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
143 | golang.org/x/net v0.0.0-20200421231249-e086a090c8fd/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
144 | golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
145 | golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
146 | golang.org/x/net v0.0.0-20210226101413-39120d07d75e/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
147 | golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
148 | golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
149 | golang.org/x/net v0.0.0-20210510120150-4163338589ed/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
150 | golang.org/x/net v0.0.0-20210614182718-04defd469f4e h1:XpT3nA5TvE525Ne3hInMh6+GETgn27Zfm9dxsThnX2Q=
151 | golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
152 | golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
153 | golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
154 | golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
155 | golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
156 | golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
157 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
158 | golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
159 | golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
160 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
161 | golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
162 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
163 | golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
164 | golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
165 | golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
166 | golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
167 | golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
168 | golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
169 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
170 | golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
171 | golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
172 | golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
173 | golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
174 | golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
175 | golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c h1:F1jZWGFhYfh0Ci55sIpILtKKK8p3i2/krTr0H1rg74I=
176 | golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
177 | golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
178 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
179 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
180 | golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
181 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
182 | golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
183 | golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
184 | golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
185 | golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
186 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
187 | golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
188 | golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
189 | golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
190 | golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
191 | golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
192 | golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
193 | golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
194 | golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
195 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
196 | golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
197 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
198 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
199 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
200 | google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
201 | google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
202 | google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
203 | google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
204 | google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
205 | google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
206 | google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
207 | google.golang.org/genproto v0.0.0-20210114201628-6edceaf6022f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
208 | google.golang.org/genproto v0.0.0-20210630183607-d20f26d13c79 h1:s1jFTXJryg4a1mew7xv03VZD8N9XjxFhk1o4Js4WvPQ=
209 | google.golang.org/genproto v0.0.0-20210630183607-d20f26d13c79/go.mod h1:yiaVoXHpRzHGyxV3o4DktVWY4mSUErTKaeEOq6C3t3U=
210 | google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
211 | google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
212 | google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
213 | google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
214 | google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
215 | google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
216 | google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
217 | google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
218 | google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
219 | google.golang.org/grpc v1.39.0 h1:Klz8I9kdtkIN6EpHHUOMLCYhTn/2WAe5a0s1hcBkdTI=
220 | google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE=
221 | google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
222 | google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
223 | google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
224 | google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
225 | google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
226 | google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
227 | google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
228 | google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
229 | google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
230 | google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
231 | google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
232 | google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
233 | google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ=
234 | google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
235 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
236 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
237 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
238 | gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
239 | gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
240 | gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
241 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
242 | gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
243 | gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
244 | gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
245 | honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
246 | honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
247 |
--------------------------------------------------------------------------------
/order-update/main.go:
--------------------------------------------------------------------------------
1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2 | // SPDX-License-Identifier: MIT-0
3 | package main
4 |
5 | import (
6 | "context"
7 | "fmt"
8 | "log"
9 | "os"
10 |
11 | "aws-step-functions-long-lived-transactions/models"
12 |
13 | "github.com/aws/aws-lambda-go/lambda"
14 | "github.com/aws/aws-sdk-go/aws"
15 | "github.com/aws/aws-sdk-go/aws/session"
16 | "github.com/aws/aws-sdk-go/service/dynamodb"
17 | "github.com/aws/aws-sdk-go/service/dynamodb/dynamodbattribute"
18 | "github.com/aws/aws-xray-sdk-go/xray"
19 | )
20 |
21 | var dynamoDB *dynamodb.DynamoDB
22 |
23 | func init() {
24 |
25 | // Create DynamoDB client
26 | var awscfg = &aws.Config{
27 | Region: aws.String(os.Getenv("AWS_REGION")),
28 | }
29 | var sess = session.Must(session.NewSession(awscfg))
30 | dynamoDB = dynamodb.New(sess)
31 |
32 | // AWS X-Ray for AWS SDK trace
33 | xray.AWS(dynamoDB.Client)
34 |
35 | log.SetPrefix("TRACE: ")
36 | log.SetFlags(log.Ldate | log.Ltime)
37 |
38 | }
39 |
40 | // handler for the Lambda function
41 | func handler(ctx context.Context, ord models.Order) (models.Order, error) {
42 |
43 | log.Printf("[%s] - received request to update order status", ord.OrderID)
44 |
45 | order, err := getOrder(ctx, ord.OrderID)
46 | if err != nil {
47 | log.Printf("[%s] - error! %s", ord.OrderID, err.Error())
48 | return ord, models.NewErrUpdateOrderStatus(err.Error())
49 | }
50 |
51 | // Set order to status to "pending"
52 | order.OrderStatus = "Pending"
53 |
54 | err = saveOrder(ctx, order)
55 | if err != nil {
56 | log.Printf("[%s] - error! %s", ord.OrderID, err.Error())
57 | return ord, models.NewErrUpdateOrderStatus(err.Error())
58 | }
59 |
60 | // testing scenario
61 | if ord.OrderID[0:2] == "11" {
62 | return models.Order{}, models.NewErrUpdateOrderStatus("Unable to update order status for " + ord.OrderID)
63 | }
64 |
65 | log.Printf("[%s] - order status updated to pending", ord.OrderID)
66 |
67 | return ord, nil
68 | }
69 |
70 | // getOrder retrieves a specified from DynamoDB and marshals it to a Order type
71 | func getOrder(ctx context.Context, orderID string) (models.Order, error) {
72 |
73 | order := models.Order{}
74 |
75 | input := &dynamodb.GetItemInput{
76 | Key: map[string]*dynamodb.AttributeValue{
77 | "order_id": {
78 | S: aws.String(orderID),
79 | },
80 | },
81 | TableName: aws.String(os.Getenv("TABLE_NAME")),
82 | }
83 |
84 | result, err := dynamoDB.GetItemWithContext(ctx, input)
85 | if err != nil {
86 | return order, err
87 | }
88 |
89 | err = dynamodbattribute.UnmarshalMap(result.Item, &order)
90 | if err != nil {
91 | return order, fmt.Errorf("failed to DynamoDB unmarshal Order, %v", err)
92 | }
93 |
94 | return order, nil
95 | }
96 |
97 | // saveOrder persist an Order type to DynamoDB
98 | func saveOrder(ctx context.Context, order models.Order) error {
99 |
100 | marshalledOrder, err := dynamodbattribute.MarshalMap(order)
101 | if err != nil {
102 | return fmt.Errorf("failed to DynamoDB marshal Order, %v", err)
103 | }
104 |
105 | _, err = dynamoDB.PutItemWithContext(ctx, &dynamodb.PutItemInput{
106 | TableName: aws.String(os.Getenv("TABLE_NAME")),
107 | Item: marshalledOrder,
108 | })
109 | if err != nil {
110 | return fmt.Errorf("failed to put record to DynamoDB, %v", err)
111 | }
112 |
113 | return nil
114 | }
115 |
116 | func main() {
117 | lambda.Start(handler)
118 | }
119 |
--------------------------------------------------------------------------------
/order-update/main_test.go:
--------------------------------------------------------------------------------
1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2 | // SPDX-License-Identifier: MIT-0
3 | package main
4 |
5 | import (
6 | "encoding/json"
7 | "os"
8 | "reflect"
9 | "testing"
10 |
11 | "aws-step-functions-long-lived-transactions/models"
12 |
13 | "github.com/stretchr/testify/assert"
14 | )
15 |
16 | // Test Orders
17 | var scenarioErrUpdateOrderStatus = "../testdata/scenario-2.json"
18 | var scenarioSuccessfulOrder = "../testdata/scenario-7.json"
19 |
20 | func TestHandler(t *testing.T) {
21 | assert := assert.New(t)
22 |
23 | t.Run("UpdateOrder", func(t *testing.T) {
24 |
25 | input := parseOrder(scenarioSuccessfulOrder)
26 |
27 | order, err := handler(nil, input)
28 | if err != nil {
29 | t.Fatal("Error failed to trigger with an invalid request")
30 | }
31 |
32 | assert.NotEmpty(order.OrderID, "OrderID must not be empty")
33 |
34 | })
35 |
36 | }
37 | func TestErrorIsOfTypeErrProcessOrder(t *testing.T) {
38 | assert := assert.New(t)
39 |
40 | t.Run("ErrUpdateOrderStatus", func(t *testing.T) {
41 |
42 | o := parseOrder(scenarioErrUpdateOrderStatus)
43 |
44 | order, err := handler(nil, o)
45 |
46 | if assert.Error(err) {
47 | errorType := reflect.TypeOf(err)
48 | assert.Equal(errorType.String(), "*models.ErrUpdateOrderStatus", "Type does not match *models.ErrUpdateOrderStatus")
49 | assert.Empty(order.OrderID)
50 | }
51 | })
52 | }
53 |
54 | func parseOrder(filename string) models.Order {
55 | inputFile, err := os.Open(filename)
56 | if err != nil {
57 | println("opening input file", err.Error())
58 | }
59 |
60 | defer inputFile.Close()
61 |
62 | jsonParser := json.NewDecoder(inputFile)
63 |
64 | o := models.Order{}
65 | if err = jsonParser.Decode(&o); err != nil {
66 | println("parsing input file", err.Error())
67 | }
68 |
69 | return o
70 | }
71 |
--------------------------------------------------------------------------------
/payment-credit/Makefile:
--------------------------------------------------------------------------------
1 | .PHONY: build-CreditPaymentFunction
2 |
3 | build-CreditPaymentFunction:
4 | GOOS=linux go build -o bootstrap
5 | cp ./bootstrap $(ARTIFACTS_DIR)/.
--------------------------------------------------------------------------------
/payment-credit/go.mod:
--------------------------------------------------------------------------------
1 | module aws-step-functions-long-lived-transactions/paymentment-credit
2 |
3 | go 1.16
4 |
5 | require (
6 | aws-step-functions-long-lived-transactions/models v0.0.0-00010101000000-000000000000
7 | github.com/andybalholm/brotli v1.0.3 // indirect
8 | github.com/aws-samples/aws-step-functions-long-lived-transactions v0.0.0-20191001081655-c5ca1f79a412
9 | github.com/aws/aws-lambda-go v1.24.0
10 | github.com/aws/aws-sdk-go v1.38.70
11 | github.com/aws/aws-xray-sdk-go v1.5.0
12 | github.com/klauspost/compress v1.13.1 // indirect
13 | github.com/stretchr/testify v1.6.1
14 | github.com/urfave/cli v1.22.1 // indirect
15 | github.com/valyala/fasthttp v1.28.0 // indirect
16 | golang.org/x/net v0.0.0-20210614182718-04defd469f4e // indirect
17 | golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c // indirect
18 | google.golang.org/genproto v0.0.0-20210630183607-d20f26d13c79 // indirect
19 | google.golang.org/grpc v1.39.0 // indirect
20 | )
21 |
22 | replace aws-step-functions-long-lived-transactions/models => ../models
23 |
--------------------------------------------------------------------------------
/payment-credit/main.go:
--------------------------------------------------------------------------------
1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2 | // SPDX-License-Identifier: MIT-0
3 | package main
4 |
5 | import (
6 | "context"
7 | "fmt"
8 | "log"
9 | "os"
10 |
11 | "aws-step-functions-long-lived-transactions/models"
12 |
13 | "github.com/aws/aws-lambda-go/lambda"
14 | "github.com/aws/aws-sdk-go/aws"
15 | "github.com/aws/aws-sdk-go/aws/session"
16 | "github.com/aws/aws-sdk-go/service/dynamodb"
17 | "github.com/aws/aws-sdk-go/service/dynamodb/dynamodbattribute"
18 | "github.com/aws/aws-xray-sdk-go/xray"
19 | )
20 |
21 | var dynamoDB *dynamodb.DynamoDB
22 |
23 | func init() {
24 |
25 | // create DynamoDB client
26 | var awscfg = &aws.Config{
27 | Region: aws.String(os.Getenv("AWS_REGION")),
28 | }
29 | var sess = session.Must(session.NewSession(awscfg))
30 | dynamoDB = dynamodb.New(sess)
31 |
32 | // AWS X-Ray for AWS SDK trace
33 | xray.AWS(dynamoDB.Client)
34 |
35 | log.SetPrefix("TRACE: ")
36 | log.SetFlags(log.Ldate | log.Ltime)
37 |
38 | }
39 |
40 | func handler(ctx context.Context, ord models.Order) (models.Order, error) {
41 |
42 | log.Printf("[%s] - processing refund", ord.OrderID)
43 |
44 | // find Payment transaction for this order
45 | payment, err := getTransaction(ctx, ord.OrderID)
46 | if err != nil {
47 | log.Printf("[%s] - error! %s", ord.OrderID, err.Error())
48 | return ord, models.NewErrProcessRefund(err.Error())
49 | }
50 |
51 | // process the refund for the order
52 | payment.Refund()
53 |
54 | // write to database.
55 | err = saveTransaction(ctx, payment)
56 | if err != nil {
57 | log.Printf("[%s] - error! %s", ord.OrderID, err.Error())
58 | return ord, models.NewErrProcessRefund(err.Error())
59 | }
60 |
61 | // save state
62 | ord.Payment = payment
63 |
64 | // testing scenario
65 | if ord.OrderID[0:2] == "22" {
66 | return ord, models.NewErrProcessRefund("Unable to process refund for order " + ord.OrderID)
67 | }
68 |
69 | log.Printf("[%s] - refund processed", ord.OrderID)
70 |
71 | return ord, nil
72 | }
73 |
74 | func main() {
75 | lambda.Start(handler)
76 | }
77 |
78 | // returns a specified payment transaction from the database
79 | func getTransaction(ctx context.Context, orderID string) (models.Payment, error) {
80 |
81 | payment := models.Payment{}
82 |
83 | input := &dynamodb.QueryInput{
84 | ExpressionAttributeValues: map[string]*dynamodb.AttributeValue{
85 | ":v1": {
86 | S: aws.String(orderID),
87 | },
88 | ":v2": {
89 | S: aws.String("Debit"),
90 | },
91 | },
92 | KeyConditionExpression: aws.String("order_id = :v1 AND payment_type = :v2"),
93 | TableName: aws.String(os.Getenv("TABLE_NAME")),
94 | IndexName: aws.String("orderIDIndex"),
95 | }
96 |
97 | // Get payment transaction from database
98 | result, err := dynamoDB.QueryWithContext(ctx, input)
99 | if err != nil {
100 | return payment, err
101 | }
102 |
103 | err = dynamodbattribute.UnmarshalMap(result.Items[0], &payment)
104 | if err != nil {
105 | return payment, fmt.Errorf("failed to DynamoDB unmarshal Payment, %v", err)
106 | }
107 |
108 | return payment, nil
109 | }
110 |
111 | // saves refund transaction to the database
112 | func saveTransaction(ctx context.Context, payment models.Payment) error {
113 |
114 | marshalledPaymentTransaction, err := dynamodbattribute.MarshalMap(payment)
115 | if err != nil {
116 | return fmt.Errorf("failed to DynamoDB marshal Payment, %v", err)
117 | }
118 |
119 | _, err = dynamoDB.PutItemWithContext(ctx, &dynamodb.PutItemInput{
120 | TableName: aws.String(os.Getenv("TABLE_NAME")),
121 | Item: marshalledPaymentTransaction,
122 | })
123 |
124 | if err != nil {
125 | return fmt.Errorf("failed to put record to DynamoDB, %v", err)
126 | }
127 | return nil
128 | }
129 |
--------------------------------------------------------------------------------
/payment-credit/main_test.go:
--------------------------------------------------------------------------------
1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2 | // SPDX-License-Identifier: MIT-0
3 | package main
4 |
5 | import (
6 | "encoding/json"
7 | "fmt"
8 | "os"
9 | "reflect"
10 | "testing"
11 |
12 | "github.com/aws-samples/aws-step-functions-long-lived-transactions/models"
13 | "github.com/stretchr/testify/assert"
14 | )
15 |
16 | // Test Orders
17 | var scenarioErrProcessRefund = "../testdata/scenario-4.json"
18 | var scenarioSuccessfulOrder = "../testdata/scenario-7.json"
19 |
20 | func TestHandler(t *testing.T) {
21 | assert := assert.New(t)
22 |
23 | t.Run("ProcessRefund", func(t *testing.T) {
24 |
25 | input := parseOrder(scenarioSuccessfulOrder)
26 |
27 | order, err := handler(nil, input)
28 | if err != nil {
29 | t.Fatal("Error failed to trigger with an invalid request")
30 | }
31 |
32 | assert.NotEmpty(order.Payment.TransactionID, "OrderID must be empty")
33 | })
34 |
35 | }
36 |
37 | func TestErrorIsOfTypeErrProcessRefund(t *testing.T) {
38 | assert := assert.New(t)
39 | t.Run("ErrProcessRefund", func(t *testing.T) {
40 |
41 | input := parseOrder(scenarioErrProcessRefund)
42 |
43 | order, err := handler(nil, input)
44 | if err != nil {
45 | fmt.Print(err)
46 | }
47 |
48 | if assert.Error(err) {
49 | errorType := reflect.TypeOf(err)
50 | assert.Equal(errorType.String(), "*models.ErrProcessRefund", "Type does not match *models.ErrProcessRefund")
51 | assert.Empty(order.OrderID)
52 | }
53 | })
54 | }
55 |
56 | func parseOrder(filename string) models.Order {
57 | inputFile, err := os.Open(filename)
58 | if err != nil {
59 | println("opening input file", err.Error())
60 | }
61 |
62 | defer inputFile.Close()
63 |
64 | jsonParser := json.NewDecoder(inputFile)
65 |
66 | o := models.Order{}
67 | if err = jsonParser.Decode(&o); err != nil {
68 | println("parsing input file", err.Error())
69 | }
70 |
71 | return o
72 | }
73 |
--------------------------------------------------------------------------------
/payment-debit/Makefile:
--------------------------------------------------------------------------------
1 | .PHONY: build-DebitPaymentFunction
2 |
3 | build-DebitPaymentFunction:
4 | GOOS=linux go build -o bootstrap
5 | cp ./bootstrap $(ARTIFACTS_DIR)/.
--------------------------------------------------------------------------------
/payment-debit/go.mod:
--------------------------------------------------------------------------------
1 | module aws-step-functions-long-lived-transactions/paymentment-debit
2 |
3 | go 1.16
4 |
5 | require (
6 | aws-step-functions-long-lived-transactions/models v0.0.0-00010101000000-000000000000
7 | github.com/andybalholm/brotli v1.0.3 // indirect
8 | github.com/aws/aws-lambda-go v1.24.0
9 | github.com/aws/aws-sdk-go v1.38.70
10 | github.com/aws/aws-xray-sdk-go v1.5.0
11 | github.com/klauspost/compress v1.13.1 // indirect
12 | github.com/stretchr/testify v1.7.0
13 | github.com/urfave/cli v1.22.1 // indirect
14 | github.com/valyala/fasthttp v1.28.0 // indirect
15 | golang.org/x/net v0.0.0-20210614182718-04defd469f4e // indirect
16 | golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c // indirect
17 | google.golang.org/genproto v0.0.0-20210630183607-d20f26d13c79 // indirect
18 | google.golang.org/grpc v1.39.0 // indirect
19 | )
20 |
21 | replace aws-step-functions-long-lived-transactions/models => ../models
22 |
--------------------------------------------------------------------------------
/payment-debit/main.go:
--------------------------------------------------------------------------------
1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2 | // SPDX-License-Identifier: MIT-0
3 | package main
4 |
5 | import (
6 | "context"
7 | "fmt"
8 | "log"
9 | "os"
10 |
11 | "aws-step-functions-long-lived-transactions/models"
12 |
13 | "github.com/aws/aws-sdk-go/aws"
14 | "github.com/aws/aws-sdk-go/aws/session"
15 | "github.com/aws/aws-sdk-go/service/dynamodb"
16 | "github.com/aws/aws-sdk-go/service/dynamodb/dynamodbattribute"
17 | "github.com/aws/aws-xray-sdk-go/xray"
18 |
19 | "github.com/aws/aws-lambda-go/lambda"
20 | )
21 |
22 | var dynamoDB *dynamodb.DynamoDB
23 |
24 | func init() {
25 |
26 | // Create DynamoDB client
27 | var awscfg = &aws.Config{
28 | Region: aws.String(os.Getenv("AWS_REGION")),
29 | }
30 | var sess = session.Must(session.NewSession(awscfg))
31 | dynamoDB = dynamodb.New(sess)
32 | xray.AWS(dynamoDB.Client)
33 |
34 | log.SetPrefix("TRACE: ")
35 | log.SetFlags(log.Ldate | log.Ltime)
36 |
37 | }
38 |
39 | func handler(ctx context.Context, ord models.Order) (models.Order, error) {
40 |
41 | log.Printf("[%s] - processing payment", ord.OrderID)
42 |
43 | var payment = models.Payment{
44 | OrderID: ord.OrderID,
45 | MerchantID: "merch1",
46 | PaymentAmount: ord.Total(),
47 | }
48 |
49 | // Process payment
50 | payment.Pay()
51 |
52 | // Save payment
53 | err := savePayment(ctx, payment)
54 | if err != nil {
55 | log.Printf("[%s] - error! %s", ord.OrderID, err.Error())
56 | return ord, models.NewErrProcessPayment(err.Error())
57 | }
58 |
59 | // Save state
60 | ord.Payment = payment
61 |
62 | // testing scenario
63 | if ord.OrderID[0:1] == "2" {
64 | return models.Order{}, models.NewErrProcessPayment("Unable to process payment for order " + ord.OrderID)
65 | }
66 |
67 | log.Printf("[%s] - payment processed", ord.OrderID)
68 |
69 | return ord, nil
70 | }
71 |
72 | func savePayment(ctx context.Context, payment models.Payment) error {
73 |
74 | marshalledOrder, err := dynamodbattribute.MarshalMap(payment)
75 | if err != nil {
76 | return fmt.Errorf("failed to DynamoDB marshal Payment, %v", err)
77 | }
78 |
79 | _, err = dynamoDB.PutItemWithContext(ctx, &dynamodb.PutItemInput{
80 | TableName: aws.String(os.Getenv("TABLE_NAME")),
81 | Item: marshalledOrder,
82 | })
83 |
84 | if err != nil {
85 | return fmt.Errorf("failed to put record to DynamoDB, %v", err)
86 | }
87 |
88 | return nil
89 | }
90 |
91 | func main() {
92 | lambda.Start(handler)
93 | }
94 |
--------------------------------------------------------------------------------
/payment-debit/main_test.go:
--------------------------------------------------------------------------------
1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2 | // SPDX-License-Identifier: MIT-0
3 | package main
4 |
5 | import (
6 | "encoding/json"
7 | "fmt"
8 | "os"
9 | "reflect"
10 | "testing"
11 |
12 | "aws-step-functions-long-lived-transactions/models"
13 |
14 | "github.com/stretchr/testify/assert"
15 | )
16 |
17 | // Test Orders
18 | var scenarioErrProcessPayment = "../testdata/scenario-3.json"
19 | var scenarioSuccessfulOrder = "../testdata/scenario-7.json"
20 |
21 | func TestHandler(t *testing.T) {
22 | assert := assert.New(t)
23 |
24 | t.Run("ProcessPayment", func(t *testing.T) {
25 |
26 | input := parseOrder(scenarioSuccessfulOrder)
27 |
28 | order, err := handler(nil, input)
29 | if err != nil {
30 | t.Fatal("Error failed to trigger with an invalid request")
31 | }
32 |
33 | assert.NotEmpty(order.Payment.TransactionID, "PaymentTransactionID must not be empty")
34 |
35 | })
36 | }
37 |
38 | func TestErrorIsOfTypeErrProcessPayment(t *testing.T) {
39 | assert := assert.New(t)
40 | t.Run("ProcessPaymentErr", func(t *testing.T) {
41 |
42 | input := parseOrder(scenarioErrProcessPayment)
43 |
44 | order, err := handler(nil, input)
45 | if err != nil {
46 | fmt.Print(err)
47 | }
48 |
49 | if assert.Error(err) {
50 | errorType := reflect.TypeOf(err)
51 | assert.Equal(errorType.String(), "*models.ErrProcessPayment", "Type does not match *models.ErrProcessPayment")
52 | assert.Empty(order.OrderID)
53 | }
54 | })
55 | }
56 |
57 | func parseOrder(filename string) models.Order {
58 | inputFile, err := os.Open(filename)
59 | if err != nil {
60 | println("opening input file", err.Error())
61 | }
62 |
63 | defer inputFile.Close()
64 |
65 | jsonParser := json.NewDecoder(inputFile)
66 |
67 | o := models.Order{}
68 | if err = jsonParser.Decode(&o); err != nil {
69 | println("parsing input file", err.Error())
70 | }
71 |
72 | return o
73 | }
74 |
--------------------------------------------------------------------------------
/statemachine/llt.asl.yaml:
--------------------------------------------------------------------------------
1 | # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2 | # SPDX-License-Identifier: MIT-0
3 | Comment: "Managing Long Lived Transactions with AWS Step Functions State Machine"
4 | StartAt: ProcessOrder
5 | TimeoutSeconds: 15
6 | States:
7 | ProcessOrder:
8 | Type: Task
9 | Resource: 'arn:aws:states:::lambda:invoke'
10 | OutputPath: $.Payload
11 | Parameters:
12 | Payload.$: $
13 | FunctionName: "${NewOrderFunction}"
14 | Retry:
15 | - ErrorEquals:
16 | - Lambda.ServiceException
17 | - Lambda.AWSLambdaException
18 | - Lambda.SdkClientException
19 | IntervalSeconds: 2
20 | MaxAttempts: 6
21 | BackoffRate: 2
22 | Next: ProcessPayment
23 | Comment: First transaction to save the order and set the order status to new
24 | Catch:
25 | - ErrorEquals:
26 | - ErrProcessOrder
27 | Next: UpdateOrderStatus
28 | ResultPath: $.error
29 | TimeoutSeconds: 10
30 |
31 | ProcessPayment:
32 | Type: Task
33 | Resource: 'arn:aws:states:::lambda:invoke'
34 | OutputPath: $.Payload
35 | Parameters:
36 | Payload.$: $
37 | FunctionName: "${DebitPaymentFunction}"
38 | Retry:
39 | - ErrorEquals:
40 | - Lambda.ServiceException
41 | - Lambda.AWSLambdaException
42 | - Lambda.SdkClientException
43 | IntervalSeconds: 2
44 | MaxAttempts: 6
45 | BackoffRate: 2
46 | Next: ReserveInventory
47 | Comment: Task processes the order payment
48 | Catch:
49 | - ErrorEquals:
50 | - ErrProcessPayment
51 | Next: ProcessRefund
52 | ResultPath: $.error
53 | TimeoutSeconds: 10
54 |
55 | ReserveInventory:
56 | Type: Task
57 | Resource: 'arn:aws:states:::lambda:invoke'
58 | OutputPath: $.Payload
59 | Parameters:
60 | Payload.$: $
61 | FunctionName: "${ReserveInventoryFunction}"
62 | Retry:
63 | - ErrorEquals:
64 | - Lambda.ServiceException
65 | - Lambda.AWSLambdaException
66 | - Lambda.SdkClientException
67 | IntervalSeconds: 2
68 | MaxAttempts: 6
69 | BackoffRate: 2
70 | Next: "sns:NotifySuccess"
71 | Comment: Task to reserve order items in inventory
72 | Catch:
73 | - ErrorEquals:
74 | - ErrReserveInventory
75 | Next: ReleaseInventory
76 | ResultPath: $.error
77 | TimeoutSeconds: 10
78 |
79 | "sns:NotifySuccess":
80 | Type: Task
81 | Resource: "arn:aws:states:::sns:publish"
82 | Parameters:
83 | Message.$: $.order_id
84 | TopicArn: "${SagaTopic}"
85 | ResultPath: $.notification
86 | Next: OrderSucceeded
87 | OrderSucceeded:
88 | Type: Succeed
89 |
90 | ReleaseInventory:
91 | Type: Task
92 | Resource: 'arn:aws:states:::lambda:invoke'
93 | OutputPath: $.Payload
94 | Parameters:
95 | Payload.$: $
96 | FunctionName: "${ReleaseInventoryFunction}"
97 | Retry:
98 | - ErrorEquals:
99 | - Lambda.ServiceException
100 | - Lambda.AWSLambdaException
101 | - Lambda.SdkClientException
102 | IntervalSeconds: 2
103 | MaxAttempts: 6
104 | BackoffRate: 2
105 | Next: ProcessRefund
106 | Comment: Task to release order items back to inventory
107 | Catch:
108 | - ErrorEquals:
109 | - ErrReleaseInventory
110 | Next: "sns:NotifyReleaseInventoryFail"
111 | ResultPath: $.error
112 | TimeoutSeconds: 10
113 |
114 | "sns:NotifyReleaseInventoryFail":
115 | Type: Task
116 | Resource: "arn:aws:states:::sns:publish"
117 | Parameters:
118 | Message.$: $.order_id
119 | TopicArn: "${SagaTopic}"
120 | ResultPath: $.notification
121 | Next: OrderFailed
122 |
123 | ProcessRefund:
124 | Type: Task
125 | Resource: 'arn:aws:states:::lambda:invoke'
126 | OutputPath: $.Payload
127 | Parameters:
128 | Payload.$: $
129 | FunctionName: "${CreditPaymentFunction}"
130 | Retry:
131 | - ErrorEquals:
132 | - Lambda.ServiceException
133 | - Lambda.AWSLambdaException
134 | - Lambda.SdkClientException
135 | IntervalSeconds: 2
136 | MaxAttempts: 6
137 | BackoffRate: 2
138 | Next: UpdateOrderStatus
139 | Comment: Task to process order refund
140 | Catch:
141 | - ErrorEquals:
142 | - ErrProcessRefund
143 | Next: "sns:NotifyProcessRefundFail"
144 | ResultPath: $.error
145 | TimeoutSeconds: 10
146 |
147 | "sns:NotifyProcessRefundFail":
148 | Type: Task
149 | Resource: "arn:aws:states:::sns:publish"
150 | Parameters:
151 | Message.$: $.order_id
152 | TopicArn: "${SagaTopic}"
153 | ResultPath: $.notification
154 | Next: OrderFailed
155 |
156 | UpdateOrderStatus:
157 | Type: Task
158 | Resource: 'arn:aws:states:::lambda:invoke'
159 | OutputPath: $.Payload
160 | Parameters:
161 | Payload.$: $
162 | FunctionName: "${UpdateOrderFunction}"
163 | Retry:
164 | - ErrorEquals:
165 | - Lambda.ServiceException
166 | - Lambda.AWSLambdaException
167 | - Lambda.SdkClientException
168 | IntervalSeconds: 2
169 | MaxAttempts: 6
170 | BackoffRate: 2
171 | Next: OrderFailed
172 | Comment: Task sets the order status to "pending".
173 | Catch:
174 | - ErrorEquals:
175 | - ErrUpdateOrderStatus
176 | Next: "sns:NotifyUpdateOrderFail"
177 | ResultPath: $.error
178 | TimeoutSeconds: 10
179 |
180 | "sns:NotifyUpdateOrderFail":
181 | Type: Task
182 | Resource: "arn:aws:states:::sns:publish"
183 | Parameters:
184 | Message.$: $.order_id
185 | TopicArn: "${SagaTopic}"
186 | ResultPath: $.notification
187 | Next: OrderFailed
188 |
189 | OrderFailed:
190 | Type: Fail
191 |
--------------------------------------------------------------------------------
/template.yaml:
--------------------------------------------------------------------------------
1 | # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2 | # SPDX-License-Identifier: MIT-0
3 | AWSTemplateFormatVersion: "2010-09-09"
4 | Transform: AWS::Serverless-2016-10-31
5 | Description: >
6 | Managing Long Lived Transactions with AWS Step Functions. AWS Step Functions is a fully managed
7 | Serverless workflow management service for managing long running processes and coordinating the
8 | components of distributed applications and microservices using visual workflows. This sample application
9 | demonstrates how you can deal with the complexities of distributed transactions and using AWS Step
10 | Functions implement the Saga design pattern.
11 |
12 | ###### ## ####### ######## ### ## ######
13 | ## ## ## ## ## ## ## ## ## ## ## ##
14 | ## ## ## ## ## ## ## ## ## ##
15 | ## #### ## ## ## ######## ## ## ## ######
16 | ## ## ## ## ## ## ## ######### ## ##
17 | ## ## ## ## ## ## ## ## ## ## ## ##
18 | ###### ######## ####### ######## ## ## ######## ######
19 |
20 | # More info about Globals: https://github.com/awslabs/serverless-application-model/blob/master/docs/globals.rst
21 | Globals:
22 | Function:
23 | Tracing: Active
24 | Handler: bootstrap
25 | Runtime: provided.al2
26 | MemorySize: 256
27 | Timeout: 15
28 | Tags:
29 | source: aws
30 | project: Managing Long Lived Transactions with AWS Step Functions
31 |
32 | Resources:
33 | ## ### ## ## ######## ######## ###
34 | ## ## ## ### ### ## ## ## ## ## ##
35 | ## ## ## #### #### ## ## ## ## ## ##
36 | ## ## ## ## ### ## ######## ## ## ## ##
37 | ## ######### ## ## ## ## ## ## #########
38 | ## ## ## ## ## ## ## ## ## ## ##
39 | ######## ## ## ## ## ######## ######## ## ##
40 |
41 | # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction
42 |
43 | # NewOrderFunction represents task to create a new order and set status to "new order"
44 | NewOrderFunction:
45 | Type: AWS::Serverless::Function
46 | Properties:
47 | CodeUri: ./order-new
48 | Policies:
49 | - DynamoDBCrudPolicy:
50 | TableName: !Ref OrdersTable
51 | Environment:
52 | Variables:
53 | TABLE_NAME: !Ref OrdersTable
54 |
55 | NewOrderFunctionLogGroup:
56 | Type: AWS::Logs::LogGroup
57 | DependsOn: [ NewOrderFunction ]
58 | Properties:
59 | LogGroupName: !Sub /aws/lambda/${NewOrderFunction}
60 | RetentionInDays: 7
61 |
62 | # UpdateOrderFunction represents the compensating transaction to set order status to "pending"
63 | UpdateOrderFunction:
64 | Type: AWS::Serverless::Function
65 | Properties:
66 | CodeUri: ./order-update
67 | Policies:
68 | - DynamoDBCrudPolicy:
69 | TableName: !Ref OrdersTable
70 | Environment:
71 | Variables:
72 | TABLE_NAME: !Ref OrdersTable
73 |
74 | UpdateOrderFunctionLogGroup:
75 | Type: AWS::Logs::LogGroup
76 | DependsOn: [ UpdateOrderFunction ]
77 | Properties:
78 | LogGroupName: !Sub /aws/lambda/${UpdateOrderFunction}
79 | RetentionInDays: 7
80 |
81 | # DebitPaymentFunction
82 | DebitPaymentFunction:
83 | Type: AWS::Serverless::Function
84 | Properties:
85 | CodeUri: ./payment-debit
86 | Role: !Sub ${PaymentFunctionsRole.Arn}
87 | Environment:
88 | Variables:
89 | TABLE_NAME: !Ref PaymentsTable
90 |
91 | DebitPaymentFunctionLogGroup:
92 | Type: AWS::Logs::LogGroup
93 | DependsOn: [ DebitPaymentFunction ]
94 | Properties:
95 | LogGroupName: !Sub /aws/lambda/${DebitPaymentFunction}
96 | RetentionInDays: 7
97 |
98 | # CreditPaymentFunction represents the compensating transaction to refund customer order
99 | CreditPaymentFunction:
100 | Type: AWS::Serverless::Function
101 | Properties:
102 | CodeUri: ./payment-credit
103 | Role: !Sub ${PaymentFunctionsRole.Arn}
104 | Environment:
105 | Variables:
106 | TABLE_NAME: !Ref PaymentsTable
107 |
108 | CreditPaymentFunctionLogGroup:
109 | Type: AWS::Logs::LogGroup
110 | DependsOn: [ CreditPaymentFunction ]
111 | Properties:
112 | LogGroupName: !Sub /aws/lambda/${CreditPaymentFunction}
113 | RetentionInDays: 7
114 |
115 | # ReserveInventoryFunction represents task to reserve/remove order items from the inventory
116 | ReserveInventoryFunction:
117 | Type: AWS::Serverless::Function
118 | Properties:
119 | CodeUri: ./inventory-reserve
120 | Role: !Sub ${InventoryFunctionsRole.Arn}
121 | Environment:
122 | Variables:
123 | TABLE_NAME: !Ref InventoryTable
124 |
125 | ReserveInventoryFunctionLogGroup:
126 | Type: AWS::Logs::LogGroup
127 | DependsOn: [ ReserveInventoryFunction ]
128 | Properties:
129 | LogGroupName: !Sub /aws/lambda/${ReserveInventoryFunction}
130 | RetentionInDays: 7
131 |
132 | # ReleaseInventoryFunction represents the compensating transaction to reverses the changes to the inventory
133 | ReleaseInventoryFunction:
134 | Type: AWS::Serverless::Function
135 | Properties:
136 | CodeUri: ./inventory-release
137 | Role: !Sub ${InventoryFunctionsRole.Arn}
138 | Environment:
139 | Variables:
140 | TABLE_NAME: !Ref InventoryTable
141 |
142 | ReleaseInventoryFunctionLogGroup:
143 | Type: AWS::Logs::LogGroup
144 | DependsOn: [ ReleaseInventoryFunction ]
145 | Properties:
146 | LogGroupName: !Sub /aws/lambda/${ReleaseInventoryFunction}
147 | RetentionInDays: 7
148 |
149 | ###### ######## ######## ######## ######## ## ## ## ## ###### ######## #### ####### ## ## ######
150 | ## ## ## ## ## ## ## ## ## ### ## ## ## ## ## ## ## ### #### ##
151 | ## ## ## ## ## ## ## ## #### ## ## ## ## ## ## #### ####
152 | ###### ## ###### ######## ###### ## ## ## ## ## ## ## ## ## ## ## ## ## ######
153 | ## ## ## ## ## ## ## ## #### ## ## ## ## ## ## #### ##
154 | ## ## ## ## ## ## ## ## ## ### ## ## ## ## ## ## ## ##### ##
155 | ###### ## ######## ## ## ####### ## ## ###### ## #### ####### ## ## ######
156 |
157 | # TODO: Add your Step Function resource here
158 | SagaStateMachine:
159 | Type: "AWS::Serverless::StateMachine"
160 | Properties:
161 | DefinitionUri: statemachine/llt.asl.yaml
162 | DefinitionSubstitutions:
163 | NewOrderFunction: !GetAtt NewOrderFunction.Arn
164 | UpdateOrderFunction: !GetAtt UpdateOrderFunction.Arn
165 | ReserveInventoryFunction: !GetAtt ReserveInventoryFunction.Arn
166 | ReleaseInventoryFunction: !GetAtt ReleaseInventoryFunction.Arn
167 | DebitPaymentFunction: !GetAtt DebitPaymentFunction.Arn
168 | CreditPaymentFunction: !GetAtt CreditPaymentFunction.Arn
169 | SagaTopic: !Ref SagaTopic
170 | Policies:
171 | - SNSPublishMessagePolicy:
172 | TopicName: !GetAtt SagaTopic.TopicName
173 | - LambdaInvokePolicy:
174 | FunctionName: !Ref NewOrderFunction
175 | - LambdaInvokePolicy:
176 | FunctionName: !Ref UpdateOrderFunction
177 | - LambdaInvokePolicy:
178 | FunctionName: !Ref ReserveInventoryFunction
179 | - LambdaInvokePolicy:
180 | FunctionName: !Ref ReleaseInventoryFunction
181 | - LambdaInvokePolicy:
182 | FunctionName: !Ref DebitPaymentFunction
183 | - LambdaInvokePolicy:
184 | FunctionName: !Ref CreditPaymentFunction
185 | - AWSXRayDaemonWriteAccess
186 | - Version: "2012-10-17"
187 | Statement:
188 | - Effect: Allow
189 | Action:
190 | - "logs:CreateLogDelivery"
191 | - "logs:GetLogDelivery"
192 | - "logs:UpdateLogDelivery"
193 | - "logs:DeleteLogDelivery"
194 | - "logs:ListLogDeliveries"
195 | - "logs:PutResourcePolicy"
196 | - "logs:DescribeResourcePolicies"
197 | - "logs:DescribeLogGroups"
198 | - "cloudwatch:PutMetricData"
199 | Resource: "*"
200 | Logging:
201 | Destinations:
202 | - CloudWatchLogsLogGroup:
203 | LogGroupArn: !GetAtt StateMachinesLogGroup.Arn
204 | Level: ALL
205 | IncludeExecutionData: True
206 | Tracing:
207 | Enabled: True
208 | Tags:
209 | source: aws
210 | project: Managing Long Lived Transactions with AWS Step Functions
211 |
212 | StateMachinesLogGroup:
213 | Type: AWS::Logs::LogGroup
214 | Properties:
215 | RetentionInDays: 3
216 | LogGroupName: llt-statemachine-logs
217 |
218 | ######## ## ## ## ## ### ## ## ####### ######## ########
219 | ## ## ## ## ### ## ## ## ### ### ## ## ## ## ## ##
220 | ## ## #### #### ## ## ## #### #### ## ## ## ## ## ##
221 | ## ## ## ## ## ## ## ## ## ### ## ## ## ## ## ########
222 | ## ## ## ## #### ######### ## ## ## ## ## ## ## ##
223 | ## ## ## ## ### ## ## ## ## ## ## ## ## ## ##
224 | ######## ## ## ## ## ## ## ## ####### ######## ########
225 |
226 | #https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlesssimpletable
227 | OrdersTable:
228 | Type: AWS::Serverless::SimpleTable
229 | Properties:
230 | PrimaryKey:
231 | Name: order_id
232 | Type: String
233 | ProvisionedThroughput:
234 | ReadCapacityUnits: 5
235 | WriteCapacityUnits: 5
236 | Tags:
237 | project: reInvent2018
238 | session: Managing Long Lived Transactions with AWS Step Functions
239 |
240 | PaymentsTable:
241 | Type: AWS::DynamoDB::Table
242 | Properties:
243 | AttributeDefinitions:
244 | - AttributeName: "transaction_id"
245 | AttributeType: "S"
246 | - AttributeName: "order_id"
247 | AttributeType: "S"
248 | - AttributeName: "payment_type"
249 | AttributeType: "S"
250 | KeySchema:
251 | - AttributeName: "transaction_id"
252 | KeyType: "HASH"
253 | ProvisionedThroughput:
254 | ReadCapacityUnits: 5
255 | WriteCapacityUnits: 5
256 | GlobalSecondaryIndexes:
257 | - IndexName: "orderIDIndex"
258 | KeySchema:
259 | - AttributeName: "order_id"
260 | KeyType: "HASH"
261 | - AttributeName: "payment_type"
262 | KeyType: "RANGE"
263 | Projection:
264 | ProjectionType: "ALL"
265 | ProvisionedThroughput:
266 | ReadCapacityUnits: 1
267 | WriteCapacityUnits: 1
268 | Tags:
269 | - Key: source
270 | Value: aws
271 | - Key: project
272 | Value: Managing Long Lived Transactions with AWS Step Functions
273 |
274 | InventoryTable:
275 | Type: AWS::DynamoDB::Table
276 | Properties:
277 | AttributeDefinitions:
278 | - AttributeName: "transaction_id"
279 | AttributeType: "S"
280 | - AttributeName: "order_id"
281 | AttributeType: "S"
282 | - AttributeName: "transaction_type"
283 | AttributeType: "S"
284 | KeySchema:
285 | - AttributeName: "transaction_id"
286 | KeyType: "HASH"
287 | ProvisionedThroughput:
288 | ReadCapacityUnits: 5
289 | WriteCapacityUnits: 5
290 | GlobalSecondaryIndexes:
291 | - IndexName: "orderIDIndex"
292 | KeySchema:
293 | - AttributeName: "order_id"
294 | KeyType: "HASH"
295 | - AttributeName: "transaction_type"
296 | KeyType: "RANGE"
297 | Projection:
298 | ProjectionType: "ALL"
299 | ProvisionedThroughput:
300 | ReadCapacityUnits: 1
301 | WriteCapacityUnits: 1
302 | Tags:
303 | - Key: source
304 | Value: aws
305 | - Key: project
306 | Value: Managing Long Lived Transactions with AWS Step Functions
307 |
308 | ###### ## ## ######
309 | ## ## ### ## ## ##
310 | ## #### ## ##
311 | ###### ## ## ## ######
312 | ## ## #### ##
313 | ## ## ## ### ## ##
314 | ###### ## ## ######
315 | SagaTopic:
316 | Type: AWS::SNS::Topic
317 | Properties:
318 | Subscription:
319 | - Endpoint: !GetAtt SagaQueue.Arn
320 | Protocol: sqs
321 | Tags:
322 | - Key: source
323 | Value: aws
324 | - Key: project
325 | Value: Managing Long Lived Transactions with AWS Step Functions
326 |
327 | ###### ####### ######
328 | ## ## ## ## ## ##
329 | ## ## ## ##
330 | ###### ## ## ######
331 | ## ## ## ## ##
332 | ## ## ## ## ## ##
333 | ###### ##### ## ######
334 |
335 | SagaQueue:
336 | Type: AWS::SQS::Queue
337 | Properties:
338 | RedrivePolicy:
339 | deadLetterTargetArn: !GetAtt SagaDeadLetterQueue.Arn
340 | maxReceiveCount: 5
341 | Tags:
342 | - Key: source
343 | Value: aws
344 | - Key: project
345 | Value: Managing Long Lived Transactions with AWS Step Functions
346 |
347 | SagaDeadLetterQueue:
348 | Type: AWS::SQS::Queue
349 | Properties:
350 | Tags:
351 | - Key: source
352 | Value: aws
353 | - Key: project
354 | Value: Managing Long Lived Transactions with AWS Step Functions
355 |
356 | SagaQueuePolicy:
357 | Type: AWS::SQS::QueuePolicy
358 | Properties:
359 | PolicyDocument:
360 | Version: "2012-10-17"
361 | Statement:
362 | - Sid: Allow-SendMessage
363 | Effect: Allow
364 | Principal:
365 | AWS: "*"
366 | Action:
367 | - sqs:SendMessage
368 | Resource: !GetAtt SagaQueue.Arn
369 | Condition:
370 | ArnEquals:
371 | "aws:SourceArn": !Ref SagaTopic
372 | Queues:
373 | - !Ref SagaQueue
374 |
375 | #### ### ## ##
376 | ## ## ## ### ###
377 | ## ## ## #### ####
378 | ## ## ## ## ### ##
379 | ## ######### ## ##
380 | ## ## ## ## ##
381 | #### ## ## ## ##
382 |
383 | InventoryFunctionsRole:
384 | Type: "AWS::IAM::Role"
385 | Properties:
386 | ManagedPolicyArns:
387 | - "arn:aws:iam::aws:policy/AWSXrayWriteOnlyAccess"
388 | - "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
389 | AssumeRolePolicyDocument:
390 | Version: "2012-10-17"
391 | Statement:
392 | - Sid: "AllowLambdaServiceToAssumeRole"
393 | Effect: "Allow"
394 | Action:
395 | - "sts:AssumeRole"
396 | Principal:
397 | Service:
398 | - "lambda.amazonaws.com"
399 | Policies:
400 | - PolicyName: "AllowCRUDOperationsOnDynamoDB"
401 | PolicyDocument:
402 | Version: "2012-10-17"
403 | Statement:
404 | - Effect: "Allow"
405 | Action:
406 | - "dynamodb:GetItem"
407 | - "dynamodb:DeleteItem"
408 | - "dynamodb:DescribeTable"
409 | - "dynamodb:PutItem"
410 | - "dynamodb:Scan"
411 | - "dynamodb:Query"
412 | - "dynamodb:UpdateItem"
413 | - "dynamodb:BatchWriteItem"
414 | - "dynamodb:BatchGetItem"
415 | Resource:
416 | - !Sub ${InventoryTable.Arn}
417 | - !Sub ${InventoryTable.Arn}/index/*
418 |
419 | PaymentFunctionsRole:
420 | Type: "AWS::IAM::Role"
421 | Properties:
422 | ManagedPolicyArns:
423 | - "arn:aws:iam::aws:policy/AWSXrayWriteOnlyAccess"
424 | - "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
425 | AssumeRolePolicyDocument:
426 | Version: "2012-10-17"
427 | Statement:
428 | - Sid: "AllowLambdaServiceToAssumeRole"
429 | Effect: "Allow"
430 | Action:
431 | - "sts:AssumeRole"
432 | Principal:
433 | Service:
434 | - "lambda.amazonaws.com"
435 | Policies:
436 | - PolicyName: "AllowCRUDOperationsOnDynamoDB"
437 | PolicyDocument:
438 | Version: "2012-10-17"
439 | Statement:
440 | - Effect: "Allow"
441 | Action:
442 | - "dynamodb:GetItem"
443 | - "dynamodb:DeleteItem"
444 | - "dynamodb:DescribeTable"
445 | - "dynamodb:PutItem"
446 | - "dynamodb:Scan"
447 | - "dynamodb:Query"
448 | - "dynamodb:UpdateItem"
449 | - "dynamodb:BatchWriteItem"
450 | - "dynamodb:BatchGetItem"
451 | Resource:
452 | - !Sub ${PaymentsTable.Arn}
453 | - !Sub ${PaymentsTable.Arn}/index/*
454 |
455 | ####### ## ## ######## ######## ## ## ######## ######
456 | ## ## ## ## ## ## ## ## ## ## ## ##
457 | ## ## ## ## ## ## ## ## ## ## ##
458 | ## ## ## ## ## ######## ## ## ## ######
459 | ## ## ## ## ## ## ## ## ## ##
460 | ## ## ## ## ## ## ## ## ## ## ##
461 | ####### ####### ## ## ####### ## ######
462 | Outputs:
463 |
464 | # NewOrderFunction
465 | NewOrderFunctionArn:
466 | Description: "Process Order Function ARN"
467 | Value: !GetAtt NewOrderFunction.Arn
468 |
469 | NewOrderFunctionIamRole:
470 | Description: "Implicit IAM Role created for Process Order function"
471 | Value: !GetAtt NewOrderFunctionRole.Arn
472 |
473 | # UpdateOrderFunction
474 | UpdateOrderFunction:
475 | Description: "Process Order Update Function ARN"
476 | Value: !GetAtt UpdateOrderFunction.Arn
477 |
478 | UpdateOrderFunctionIamRole:
479 | Description: "Implicit IAM Role created for Process Order function"
480 | Value: !GetAtt UpdateOrderFunctionRole.Arn
481 |
482 | # DebitPaymentFunction
483 | DebitPaymentFunctionArn:
484 | Description: "Process Payment Function ARN"
485 | Value: !GetAtt DebitPaymentFunction.Arn
486 |
487 | # CreditPaymentFunction
488 | CreditPaymentFunctionArn:
489 | Description: "Process Payment Refund Function ARN"
490 | Value: !GetAtt CreditPaymentFunction.Arn
491 |
492 | PaymentFunctionsIamRole:
493 | Description: "Implicit IAM Role created for payment functions"
494 | Value: !GetAtt PaymentFunctionsRole.Arn
495 |
496 | # ReserveInventoryFunction
497 | ReserveInventoryFunctionArn:
498 | Description: "Reserve Inventory Function ARN"
499 | Value: !GetAtt ReserveInventoryFunction.Arn
500 |
501 | # ReleaseInventoryFunction
502 | ReleaseInventoryFunctionFunctionArn:
503 | Description: "Release Inventory Function ARN"
504 | Value: !GetAtt ReleaseInventoryFunction.Arn
505 |
506 | InventoryFunctionsIamRole:
507 | Description: "Implicit IAM Role created for inventory functions"
508 | Value: !GetAtt InventoryFunctionsRole.Arn
509 |
510 | # Step Function ARN
511 | SagaStateMachineArn:
512 | Description: Step Functions State Machine ARN
513 | Value: !Ref SagaStateMachine
514 |
515 | # DynamoDB Table ARN's
516 | OrdersTableArn:
517 | Description: "Orders table ARN"
518 | Value: !GetAtt OrdersTable.Arn
519 |
520 | PaymentsTableArn:
521 | Description: "Payments table ARN"
522 | Value: !GetAtt PaymentsTable.Arn
523 |
524 | InventoryTableArn:
525 | Description: "Inventory table ARN"
526 | Value: !GetAtt InventoryTable.Arn
527 |
--------------------------------------------------------------------------------
/testdata/scenario-1.json:
--------------------------------------------------------------------------------
1 | {
2 | "order_id": "1ae4501d-ed92-4b27-bf0e-fd978ed45127",
3 | "order_date": "2018-10-19T10:50:16+08:00",
4 | "customer_id": "8d04ea6f-c6b2-4422-8550-839a16f01feb",
5 | "items": [{
6 | "item_id": "987",
7 | "qty": 1.0,
8 | "description": "Cart item 1",
9 | "unit_price": 19.99
10 | },
11 | {
12 | "item_id": "546",
13 | "qty": 1.0,
14 | "description": "Cart item 2",
15 | "unit_price": 23.98
16 | },
17 | {
18 | "item_id": "3",
19 | "qty": 2.0,
20 | "description": "Cart item 3",
21 | "unit_price": 6.50
22 | }
23 | ]
24 | }
--------------------------------------------------------------------------------
/testdata/scenario-2.json:
--------------------------------------------------------------------------------
1 | {
2 | "order_id": "11328abd-368d-43fd-bd4f-db15b5b63951",
3 | "order_date": "2018-10-19T10:50:16+08:00",
4 | "customer_id": "8d04ea6f-c6b2-4422-8550-839a16f01feb",
5 | "items": [{
6 | "item_id": "189",
7 | "qty": 1.0,
8 | "description": "Cart item 1",
9 | "unit_price": 19.99
10 | },
11 | {
12 | "item_id": "28",
13 | "qty": 1.0,
14 | "description": "Cart item 2",
15 | "unit_price": 23.98
16 | },
17 | {
18 | "item_id": "322",
19 | "qty": 2.0,
20 | "description": "Cart item 3",
21 | "unit_price": 6.50
22 | }
23 | ]
24 | }
--------------------------------------------------------------------------------
/testdata/scenario-3.json:
--------------------------------------------------------------------------------
1 | {
2 | "order_id": "25b0b599-441b-45c3-910e-ad63fe992c43",
3 | "order_date": "2018-10-19T10:50:16+08:00",
4 | "customer_id": "8d04ea6f-c6b2-4422-8550-839a16f01feb",
5 | "items": [{
6 | "item_id": "567",
7 | "qty": 1.0,
8 | "description": "Cart item 1",
9 | "unit_price": 199.99
10 | }
11 | ]
12 | }
--------------------------------------------------------------------------------
/testdata/scenario-4.json:
--------------------------------------------------------------------------------
1 | {
2 | "order_id": "22b0b599-441b-45c3-910e-ad63fe992c43",
3 | "order_date": "2018-10-19T10:50:16+08:00",
4 | "customer_id": "8d04ea6f-c6b2-4422-8550-839a16f01feb",
5 | "items": [{
6 | "item_id": "67",
7 | "qty": 1.0,
8 | "description": "Cart item 1",
9 | "unit_price": 19.99
10 | }
11 | ]
12 | }
--------------------------------------------------------------------------------
/testdata/scenario-5.json:
--------------------------------------------------------------------------------
1 | {
2 | "order_id": "3b7dc768-6f32-495d-a140-3d330c246f50",
3 | "order_date": "2018-10-19T10:50:16+08:00",
4 | "customer_id": "8d04ea6f-c6b2-4422-8550-839a16f01feb",
5 | "items": [{
6 | "item_id": "789",
7 | "qty": 2.0,
8 | "description": "Cart item 1",
9 | "unit_price": 190.00
10 | },
11 | {
12 | "item_id": "256",
13 | "qty": 1.0,
14 | "description": "Cart item 2",
15 | "unit_price": 99.00
16 | }
17 | ]
18 | }
--------------------------------------------------------------------------------
/testdata/scenario-6.json:
--------------------------------------------------------------------------------
1 | {
2 | "order_id": "337dc768-6f32-495d-a140-3d330c246f50",
3 | "order_date": "2018-10-19T10:50:16+08:00",
4 | "customer_id": "8d04ea6f-c6b2-4422-8550-839a16f01feb",
5 | "items": [{
6 | "item_id": "123",
7 | "qty": 2.0,
8 | "description": "Cart item 1",
9 | "unit_price": 190.00
10 | },
11 | {
12 | "item_id": "677",
13 | "qty": 1.0,
14 | "description": "Cart item 2",
15 | "unit_price": 99.00
16 | }
17 | ]
18 | }
--------------------------------------------------------------------------------
/testdata/scenario-7.json:
--------------------------------------------------------------------------------
1 | {
2 | "order_id": "40063fe3-56d9-4c51-b91f-71929834ce03",
3 | "order_date": "2018-10-19T10:50:16+08:00",
4 | "customer_id": "8d04ea6f-c6b2-4422-8550-839a16f01feb",
5 | "items": [{
6 | "item_id": "123",
7 | "qty": 1.0,
8 | "description": "Cart item 1",
9 | "unit_price": 19.99
10 | },
11 | {
12 | "item_id": "234",
13 | "qty": 1.0,
14 | "description": "Cart item 2",
15 | "unit_price": 23.98
16 | },
17 | {
18 | "item_id": "345",
19 | "qty": 2.0,
20 | "description": "Cart item 3",
21 | "unit_price": 6.50
22 | }
23 | ]
24 | }
--------------------------------------------------------------------------------