├── .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 | ![Saga with Step Functions](docs/images/stepdiagram_new.png) 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 | ![1](images/paths-breakdown-1.png) 117 | 11 | ErrUpdateOrderStatus | 11328abd-368d-43fd-bd4f-db15b5b63951 | ![11](images/paths-breakdown-11.png) 118 | 2 | ErrProcessPayment | 20b0b599-441b-45c3-910e-ad63fe992c43 | ![2](images/paths-breakdown-2.png) 119 | 22 | ErrProcessRefund | 222f741b-0292-4f93-a2f7-503f92486955 | ![22](images/paths-breakdown-22.png) 120 | 3 | ErrReserveInventory | 3a7dc768-6f32-495d-a140-3d330c246f50 | ![3](images/paths-breakdown-3.png) 121 | 33 | ErrReleaseInventory | 33a49007-a815-4079-9b9b-e30ae7eca11f | ![3](images/paths-breakdown-33.png) 122 | 4-9 | No error | 47063fe3-56d9-4c51-b91f-71929834ce03 | ![4-9](images/paths-breakdown-7.png) 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 | ![CloudFormation Output](images/cfn-output.png) 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) | [![Launch in us-east-1](http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/images/cloudformation-launch-stack-button.png)](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) | [![Launch in us-west-2](http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/images/cloudformation-launch-stack-button.png)](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) | [![Launch in ap-southeast-2](http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/images/cloudformation-launch-stack-button.png)](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 | ![Acknowledge IAM Screenshot](images/capabilities.png) 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 | } --------------------------------------------------------------------------------