@@ -1,42 +0,0 @@ | |||
# | |||
# Licensed to the Apache Software Foundation (ASF) under one or more | |||
# contributor license agreements. See the NOTICE file distributed with | |||
# this work for additional information regarding copyright ownership. | |||
# The ASF licenses this file to You under the Apache License, Version 2.0 | |||
# (the "License"); you may not use this file except in compliance with | |||
# the License. You may obtain a copy of the License at | |||
# | |||
# http://www.apache.org/licenses/LICENSE-2.0 | |||
# | |||
# Unless required by applicable law or agreed to in writing, software | |||
# distributed under the License is distributed on an "AS IS" BASIS, | |||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
# See the License for the specific language governing permissions and | |||
# limitations under the License. | |||
# | |||
github: | |||
description: "Go Implementation For Seata" | |||
homepage: https://seata.apache.org/ | |||
labels: | |||
- at | |||
- tcc | |||
- saga | |||
- xa | |||
enabled_merge_buttons: | |||
squash: true | |||
merge: false | |||
rebase: false | |||
dependabot_alerts: true | |||
dependabot_updates: false | |||
protected_branches: | |||
master: | |||
required_status_checks: | |||
strict: true | |||
required_pull_request_reviews: | |||
dismiss_stale_reviews: true | |||
required_approving_review_count: 1 | |||
notifications: | |||
commits: notifications@seata.apache.org | |||
issues: notifications@seata.apache.org | |||
pullrequests: notifications@seata.apache.org | |||
discussions: dev@seata.apache.org |
@@ -0,0 +1,15 @@ | |||
root = true | |||
[*] | |||
charset = utf-8 | |||
end_of_line = lf | |||
insert_final_newline = true | |||
indent_style = tab | |||
indent_size = 4 | |||
trim_trailing_whitespace = true | |||
[*.md] | |||
trim_trailing_whitespace = false | |||
[*.yml] | |||
indent_size = 2 |
@@ -1,122 +0,0 @@ | |||
name: "🐞 Bug 报告" | |||
description: "提交 Bug 帮助我们改进" | |||
title: "[BUG] " | |||
labels: ["bug"] | |||
body: | |||
- type: markdown | |||
attributes: | |||
value: | | |||
## 👋 感谢您的反馈! | |||
请填写以下信息帮助我们更好地理解和解决问题。 | |||
- type: checkboxes | |||
id: duplicate-check | |||
attributes: | |||
label: "✅ 验证清单" | |||
description: "请确认您已经完成以下操作:" | |||
options: | |||
- label: "🔍 我已经搜索过 [现有 Issues](https://github.com/apache/incubator-seata-go/issues),确信这不是重复问题" | |||
required: true | |||
- type: markdown | |||
attributes: | |||
value: | | |||
--- | |||
## 🔧 环境信息 | |||
- type: input | |||
id: go-version | |||
attributes: | |||
label: "🚀 Go 版本" | |||
description: "请提供您使用的 Go 版本" | |||
placeholder: "例如:1.23.0" | |||
validations: | |||
required: true | |||
- type: input | |||
id: seata-go-version | |||
attributes: | |||
label: "📦 Seata-go 版本" | |||
description: "请提供您使用的 seata-go 版本" | |||
placeholder: "例如:v1.2.0" | |||
validations: | |||
required: true | |||
- type: dropdown | |||
id: platform | |||
attributes: | |||
label: "💾 操作系统" | |||
description: "您使用的操作系统平台" | |||
options: | |||
- "🪟 Windows" | |||
- "🍎 macOS" | |||
- "🐧 Linux" | |||
validations: | |||
required: true | |||
- type: markdown | |||
attributes: | |||
value: | | |||
--- | |||
## 🐛 问题详情 | |||
- type: textarea | |||
id: bug-description | |||
attributes: | |||
label: "📝 Bug 描述" | |||
description: "请清晰简洁地描述您遇到的问题" | |||
placeholder: | | |||
请详细描述您遇到的 bug,包括: | |||
• 具体的问题现象 | |||
• 错误信息(如有) | |||
• 影响范围 | |||
validations: | |||
required: true | |||
- type: textarea | |||
id: reproduction-steps | |||
attributes: | |||
label: "🔄 重现步骤" | |||
description: "请提供详细的步骤来重现这个问题" | |||
placeholder: | | |||
请按顺序列出重现步骤: | |||
1. 第一步... | |||
2. 第二步... | |||
3. 第三步... | |||
4. 看到错误 | |||
💡 如果可能,请提供 GitHub 仓库链接或最小重现代码 | |||
validations: | |||
required: true | |||
- type: textarea | |||
id: expected-behavior | |||
attributes: | |||
label: "✅ 预期行为" | |||
description: "请描述您期望应该发生什么" | |||
placeholder: "详细描述正确的行为应该是什么样的..." | |||
validations: | |||
required: true | |||
- type: textarea | |||
id: actual-behavior | |||
attributes: | |||
label: "❌ 实际行为" | |||
description: "请描述实际发生了什么" | |||
placeholder: | | |||
详细描述实际发生的情况,包括: | |||
• 错误消息 | |||
• 异常堆栈 | |||
• 日志输出 | |||
validations: | |||
required: true | |||
- type: textarea | |||
id: possible-solution | |||
attributes: | |||
label: "💡 可能的解决方案" | |||
description: "如果您对解决这个问题有想法,请在此分享" | |||
placeholder: "分享您的想法、建议或已尝试的解决方案..." | |||
validations: | |||
required: false |
@@ -1,94 +0,0 @@ | |||
name: "✨ 功能请求" | |||
description: "提出新想法或功能建议" | |||
title: "[FEATURE] " | |||
labels: ["enhancement"] | |||
body: | |||
- type: markdown | |||
attributes: | |||
value: | | |||
## 🚀 功能请求 | |||
感谢您为项目提供新的想法和建议! | |||
- type: checkboxes | |||
id: verification | |||
attributes: | |||
label: "✅ 验证清单" | |||
description: "请确认您已经完成以下操作:" | |||
options: | |||
- label: "🔍 我已经搜索过 [现有 Issues](https://github.com/apache/incubator-seata-go/issues),确信这不是重复请求" | |||
required: true | |||
- label: "📋 我已经查看了 [发布说明](https://github.com/apache/incubator-seata-go/releases),确信此功能尚未实现" | |||
required: true | |||
- type: markdown | |||
attributes: | |||
value: | | |||
--- | |||
## 💡 功能详情 | |||
- type: textarea | |||
id: solution-description | |||
attributes: | |||
label: "🎯 功能描述" | |||
description: "清晰概述您建议的功能或方法" | |||
placeholder: | | |||
请详细描述您希望看到的功能,包括: | |||
• 功能的核心作用 | |||
• 预期的使用方式 | |||
• 与现有功能的关系 | |||
validations: | |||
required: true | |||
- type: textarea | |||
id: use-cases | |||
attributes: | |||
label: "📋 使用场景" | |||
description: "这个功能适用的典型场景和业务价值" | |||
placeholder: | | |||
请描述具体的使用场景: | |||
• 在什么情况下会使用这个功能? | |||
• 解决了什么具体问题? | |||
• 带来什么价值? | |||
validations: | |||
required: true | |||
- type: textarea | |||
id: complexity-risks | |||
attributes: | |||
label: "⚖️ 复杂性与风险评估" | |||
description: "潜在的技术挑战、实现难度或可能的风险" | |||
placeholder: | | |||
请考虑并描述: | |||
• 实现难度评估 | |||
• 可能的技术挑战 | |||
• 对现有功能的影响 | |||
• 性能考虑 | |||
validations: | |||
required: false | |||
- type: textarea | |||
id: external-dependencies | |||
attributes: | |||
label: "🔗 外部依赖" | |||
description: "实现此功能需要的第三方工具、服务或集成" | |||
placeholder: | | |||
列出所需的外部依赖: | |||
• 第三方库或框架 | |||
• 外部服务 | |||
• 特定的环境要求 | |||
validations: | |||
required: false | |||
- type: textarea | |||
id: additional-context | |||
attributes: | |||
label: "📚 附加信息" | |||
description: "任何其他相关的上下文、截图或参考资料" | |||
placeholder: | | |||
提供任何有助于理解需求的信息: | |||
• 相关文档或标准 | |||
• 参考实现 | |||
• 设计草图或截图 | |||
validations: | |||
required: false |
@@ -1,80 +0,0 @@ | |||
name: "❓ 问题咨询" | |||
description: "提出关于项目的疑问" | |||
title: "[QUESTION] " | |||
labels: ["question"] | |||
body: | |||
- type: markdown | |||
attributes: | |||
value: | | |||
## 🤔 问题咨询 | |||
我们很乐意帮助您解答关于 Seata-go 的问题! | |||
- type: checkboxes | |||
id: verification | |||
attributes: | |||
label: "✅ 验证清单" | |||
description: "请确认您已经完成以下操作:" | |||
options: | |||
- label: "🔍 我已经搜索过 [现有 Issues](https://github.com/apache/incubator-seata-go/issues),确信这不是重复问题" | |||
required: true | |||
- type: markdown | |||
attributes: | |||
value: | | |||
--- | |||
## 🔧 环境信息(可选) | |||
- type: input | |||
id: seata-go-version | |||
attributes: | |||
label: "📦 Seata-go 版本" | |||
description: "请提供您使用的 seata-go 版本" | |||
placeholder: "例如:v1.2.0" | |||
validations: | |||
required: false | |||
- type: markdown | |||
attributes: | |||
value: | | |||
--- | |||
## ❓ 问题详情 | |||
- type: textarea | |||
id: question | |||
attributes: | |||
label: "💬 您的问题" | |||
description: "请详细描述您想了解的问题" | |||
placeholder: | | |||
请详细描述您的问题,包括: | |||
• 具体想了解什么? | |||
• 遇到了什么困惑? | |||
• 期望得到什么样的帮助? | |||
validations: | |||
required: true | |||
- type: textarea | |||
id: context | |||
attributes: | |||
label: "📚 背景信息" | |||
description: "添加任何可能帮助我们回答您问题的上下文" | |||
placeholder: | | |||
提供相关背景信息: | |||
• 您在做什么项目? | |||
• 为什么需要了解这个问题? | |||
• 您已经尝试过什么? | |||
validations: | |||
required: false | |||
- type: textarea | |||
id: related-resources | |||
attributes: | |||
label: "🔗 相关资源" | |||
description: "链接到任何相关文档、代码或资源" | |||
placeholder: | | |||
分享相关链接或资源: | |||
• 相关文档链接 | |||
• 代码仓库或片段 | |||
• 参考资料 | |||
validations: | |||
required: false |
@@ -1,47 +0,0 @@ | |||
name: "📝 提案" | |||
description: "创建一个技术提案" | |||
title: "[提案] " | |||
labels: ["proposal"] | |||
body: | |||
- type: checkboxes | |||
id: verification | |||
attributes: | |||
label: "⚠️ 验证" | |||
description: "请确认您已经完成以下操作:" | |||
options: | |||
- label: 我已经搜索过 [issues](https://github.com/apache/incubator-seata-go/issues),确信这不是一个重复的提案。 | |||
required: true | |||
- type: markdown | |||
attributes: | |||
value: | | |||
## 📋 提案详情 | |||
请使用此模板提交具体的功能设计提案。 | |||
如果您只想请求新功能并讨论可能的业务价值,请创建功能请求。 | |||
- type: textarea | |||
id: proposal-summary | |||
attributes: | |||
label: "✨ 提案摘要" | |||
description: "您提案的简要概述" | |||
placeholder: "提供您的技术提案的简明摘要" | |||
validations: | |||
required: true | |||
- type: textarea | |||
id: implementation-approach | |||
attributes: | |||
label: "🛠️ 实现方法" | |||
description: "应该如何实现这个提案?" | |||
placeholder: "描述实现此提案的方法" | |||
validations: | |||
required: true | |||
- type: textarea | |||
id: additional-context | |||
attributes: | |||
label: "📚 附加上下文" | |||
description: "任何其他相关信息" | |||
placeholder: "提供可能有助于理解您提案的任何其他上下文" | |||
validations: | |||
required: false |
@@ -1,26 +0,0 @@ | |||
name: "💬 讨论" | |||
description: "开始一个关于项目的讨论" | |||
title: "[讨论] " | |||
labels: ["discussion"] | |||
body: | |||
- type: markdown | |||
attributes: | |||
value: "## 🔄 讨论主题" | |||
- type: textarea | |||
id: discussion-content | |||
attributes: | |||
label: "讨论详情" | |||
description: "请描述您想要讨论的内容" | |||
placeholder: "提供关于您想讨论的项目相关事项的详细信息" | |||
validations: | |||
required: true | |||
- type: textarea | |||
id: related-context | |||
attributes: | |||
label: "📚 相关背景" | |||
description: "添加任何相关的上下文或背景信息" | |||
placeholder: "分享有助于理解此讨论的背景信息" | |||
validations: | |||
required: false |
@@ -1,122 +0,0 @@ | |||
name: "🐞 Bug Report" | |||
description: "Report a bug to help us improve" | |||
title: "[BUG] " | |||
labels: ["bug"] | |||
body: | |||
- type: markdown | |||
attributes: | |||
value: | | |||
## 👋 Thank you for your feedback! | |||
Please fill out the following information to help us understand and resolve the issue. | |||
- type: checkboxes | |||
id: duplicate-check | |||
attributes: | |||
label: "✅ Verification Checklist" | |||
description: "Please verify that you've completed the following:" | |||
options: | |||
- label: "🔍 I have searched the [existing issues](https://github.com/apache/incubator-seata-go/issues) and confirmed this is not a duplicate" | |||
required: true | |||
- type: markdown | |||
attributes: | |||
value: | | |||
--- | |||
## 🔧 Environment Information | |||
- type: input | |||
id: go-version | |||
attributes: | |||
label: "🚀 Go Version" | |||
description: "The version of Go you're using" | |||
placeholder: "e.g., 1.23.0" | |||
validations: | |||
required: true | |||
- type: input | |||
id: seata-go-version | |||
attributes: | |||
label: "📦 Seata-go Version" | |||
description: "The version of seata-go you're using" | |||
placeholder: "e.g: v1.2.0" | |||
validations: | |||
required: true | |||
- type: dropdown | |||
id: platform | |||
attributes: | |||
label: "💾 Operating System" | |||
description: "What platform are you using?" | |||
options: | |||
- "🪟 Windows" | |||
- "🍎 macOS" | |||
- "🐧 Linux" | |||
validations: | |||
required: true | |||
- type: markdown | |||
attributes: | |||
value: | | |||
--- | |||
## 🐛 Issue Details | |||
- type: textarea | |||
id: bug-description | |||
attributes: | |||
label: "📝 Bug Description" | |||
description: "A clear and concise description of what the bug is" | |||
placeholder: | | |||
Please describe the bug in detail, including: | |||
• Specific problem symptoms | |||
• Error messages (if any) | |||
• Impact scope | |||
validations: | |||
required: true | |||
- type: textarea | |||
id: reproduction-steps | |||
attributes: | |||
label: "🔄 Steps to Reproduce" | |||
description: "Please provide detailed steps to reproduce this issue" | |||
placeholder: | | |||
Please list the steps to reproduce: | |||
1. First step... | |||
2. Second step... | |||
3. Third step... | |||
4. See error | |||
💡 If possible, please provide a GitHub repository link or minimal reproduction code | |||
validations: | |||
required: true | |||
- type: textarea | |||
id: expected-behavior | |||
attributes: | |||
label: "✅ Expected Behavior" | |||
description: "What did you expect to happen?" | |||
placeholder: "Describe in detail what the correct behavior should be..." | |||
validations: | |||
required: true | |||
- type: textarea | |||
id: actual-behavior | |||
attributes: | |||
label: "❌ Actual Behavior" | |||
description: "What actually happened?" | |||
placeholder: | | |||
Describe what actually happened, including: | |||
• Error messages | |||
• Exception stack traces | |||
• Log output | |||
validations: | |||
required: true | |||
- type: textarea | |||
id: possible-solution | |||
attributes: | |||
label: "💡 Possible Solution" | |||
description: "If you have ideas on how to fix this issue, please share them here" | |||
placeholder: "Share your thoughts, suggestions, or attempted solutions..." | |||
validations: | |||
required: false |
@@ -1,60 +0,0 @@ | |||
name: "✨ Feature Request" | |||
description: "Suggest an idea for this project" | |||
title: "[FEATURE] " | |||
labels: ["enhancement"] | |||
body: | |||
- type: checkboxes | |||
id: verification | |||
attributes: | |||
label: "⚠️ Verification" | |||
description: "Please verify that you've done the following:" | |||
options: | |||
- label: I have searched the [issues](https://github.com/apache/incubator-seata-go/issues) of this repository and believe that this is not a duplicate. | |||
required: true | |||
- label: I have searched the [release notes](https://github.com/apache/incubator-seata-go/releases) of this repository and believe that this is not a duplicate. | |||
required: true | |||
- type: textarea | |||
id: solution-description | |||
attributes: | |||
label: "🎯 Solution Description" | |||
description: "A clear overview of the proposed approach or feature." | |||
placeholder: "Describe the solution you'd like to see implemented" | |||
validations: | |||
required: true | |||
- type: textarea | |||
id: use-cases | |||
attributes: | |||
label: "📋 Use Cases" | |||
description: "Typical scenarios where this solution would be applied." | |||
placeholder: "Describe situations where this feature would be useful" | |||
validations: | |||
required: true | |||
- type: textarea | |||
id: complexity-risks | |||
attributes: | |||
label: "⚖️ Complexity & Risks" | |||
description: "Potential challenges, technical hurdles, or downsides." | |||
placeholder: "Describe any potential challenges or concerns" | |||
validations: | |||
required: false | |||
- type: textarea | |||
id: external-dependencies | |||
attributes: | |||
label: "🔗 External Dependencies" | |||
description: "Required third-party tools, services, or integrations." | |||
placeholder: "List any external tools or services needed" | |||
validations: | |||
required: false | |||
- type: textarea | |||
id: additional-context | |||
attributes: | |||
label: "📘 Additional Context" | |||
description: "Add any other context or screenshots about the feature request here." | |||
placeholder: "Add any other relevant information here" | |||
validations: | |||
required: false |
@@ -1,80 +0,0 @@ | |||
name: "❓ Question" | |||
description: "Ask a question about the project" | |||
title: "[QUESTION] " | |||
labels: ["question"] | |||
body: | |||
- type: markdown | |||
attributes: | |||
value: | | |||
## 🤔 Question | |||
We're happy to help answer your questions about Seata-go! | |||
- type: checkboxes | |||
id: verification | |||
attributes: | |||
label: "✅ Verification Checklist" | |||
description: "Please verify that you've completed the following:" | |||
options: | |||
- label: "🔍 I have searched the [existing issues](https://github.com/apache/incubator-seata-go/issues) and confirmed this is not a duplicate" | |||
required: true | |||
- type: markdown | |||
attributes: | |||
value: | | |||
--- | |||
## 🔧 Configuration (Optional)" | |||
- type: input | |||
id: seata-go-version | |||
attributes: | |||
label: "📦 Seata-go Version" | |||
description: "The version of seata-go you're using" | |||
placeholder: "e.g: v1.2.0" | |||
validations: | |||
required: false | |||
- type: markdown | |||
attributes: | |||
value: | | |||
--- | |||
## ❓ Question Details | |||
- type: textarea | |||
id: question | |||
attributes: | |||
label: "💬 Your Question" | |||
description: "Please describe your question in detail" | |||
placeholder: | | |||
Please describe your question in detail, including: | |||
• What specifically would you like to know? | |||
• What confusion have you encountered? | |||
• What kind of help are you expecting? | |||
validations: | |||
required: true | |||
- type: textarea | |||
id: context | |||
attributes: | |||
label: "📚 Background Information" | |||
description: "Add any context that might help us answer your question" | |||
placeholder: | | |||
Provide relevant background information: | |||
• What project are you working on? | |||
• Why do you need to understand this? | |||
• What have you already tried? | |||
validations: | |||
required: false | |||
- type: textarea | |||
id: related-resources | |||
attributes: | |||
label: "🔗 Related Resources" | |||
description: "Link to any related documents, code, or resources" | |||
placeholder: | | |||
Share related links or resources: | |||
• Relevant documentation links | |||
• Code repositories or snippets | |||
• Reference materials | |||
validations: | |||
required: false |
@@ -1,47 +0,0 @@ | |||
name: "📝 Proposal" | |||
description: "Create a technical proposal" | |||
title: "[PROPOSAL] " | |||
labels: ["proposal"] | |||
body: | |||
- type: checkboxes | |||
id: verification | |||
attributes: | |||
label: "⚠️ Verification" | |||
description: "Please verify that you've done the following:" | |||
options: | |||
- label: I have searched the [issues](https://github.com/apache/incubator-seata-go/issues) of this repository and believe that this is not a duplicate. | |||
required: true | |||
- type: markdown | |||
attributes: | |||
value: | | |||
## 📋 Proposal Details | |||
Please use this for a concrete design proposal for functionality. | |||
If you just want to request a new feature and discuss the possible business value, create a Feature Request instead. | |||
- type: textarea | |||
id: proposal-summary | |||
attributes: | |||
label: "✨ Proposal Summary" | |||
description: "A brief overview of your proposal" | |||
placeholder: "Provide a concise summary of your technical proposal" | |||
validations: | |||
required: true | |||
- type: textarea | |||
id: implementation-approach | |||
attributes: | |||
label: "🛠️ Implementation Approach" | |||
description: "How should this be implemented?" | |||
placeholder: "Describe the approach to implementing this proposal" | |||
validations: | |||
required: true | |||
- type: textarea | |||
id: additional-context | |||
attributes: | |||
label: "📚 Additional Context" | |||
description: "Any other relevant information" | |||
placeholder: "Provide any other context that might help understand your proposal" | |||
validations: | |||
required: false |
@@ -1,26 +0,0 @@ | |||
name: "💬 Discussion" | |||
description: "Start a discussion about the project" | |||
title: "[DISCUSSION] " | |||
labels: ["discussion"] | |||
body: | |||
- type: markdown | |||
attributes: | |||
value: "## 🔄 Discussion Topic" | |||
- type: textarea | |||
id: discussion-content | |||
attributes: | |||
label: "Discussion Details" | |||
description: "Please describe what you'd like to discuss" | |||
placeholder: "Provide details about what you want to discuss regarding the project" | |||
validations: | |||
required: true | |||
- type: textarea | |||
id: related-context | |||
attributes: | |||
label: "📚 Related Context" | |||
description: "Add any relevant context or background information" | |||
placeholder: "Share any background information that helps frame this discussion" | |||
validations: | |||
required: false |
@@ -0,0 +1,26 @@ | |||
--- | |||
name: Bug report | |||
about: Create a report to help us improve | |||
title: '' | |||
--- | |||
- [ ] I have searched the [issues](https://github.com/transaction-wg/seata-golang/issues) of this repository and believe that this is not a duplicate. | |||
**Describe the bug** | |||
A clear and concise description of what the bug is. | |||
**To Reproduce** | |||
Steps to reproduce the behavior: | |||
1. Go to '...' | |||
2. Click on '....' | |||
3. Scroll down to '....' | |||
4. See error | |||
**Expected behavior** | |||
A clear and concise description of what you expected to happen. | |||
**Screenshots** | |||
If applicable, add screenshots to help explain your problem. | |||
**Additional context** | |||
Add any other context about the problem here. |
@@ -0,0 +1,17 @@ | |||
--- | |||
name: Feature request | |||
about: Suggest an idea for this project | |||
title: '' | |||
--- | |||
**Is your feature request related to a problem? Please describe.** | |||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] | |||
**Describe the solution you'd like** | |||
A clear and concise description of what you want to happen. | |||
**Describe alternatives you've considered** | |||
A clear and concise description of any alternative solutions or features you've considered. | |||
**Additional context** | |||
Add any other context or screenshots about the feature request here. |
@@ -1,24 +1,15 @@ | |||
<!-- Thanks for sending a pull request! | |||
--> | |||
**What this PR does**: | |||
**Which issue(s) this PR fixes**: | |||
<!-- | |||
*Automatically closes linked issue when PR is merged. | |||
Usage: `Fixes #<issue number>`, or `Fixes (paste link of issue)`. | |||
_If PR is about `failing-tests or flakes`, please post the related issues/tests in a comment and do not use `Fixes`_* | |||
--> | |||
Fixes # | |||
**Special notes for your reviewer**: | |||
**Does this PR introduce a user-facing change?**: | |||
<!-- | |||
If no, just write "NONE" in the release-note block below. | |||
If yes, a release note is required: | |||
Enter your extended release note in the block below. If the PR requires additional action from users switching to the new release, include the string "action required". | |||
--> | |||
```release-note | |||
``` | |||
ref: https://github.com/seata-golang/seata-golang/issues/<issueID> | |||
### Ⅰ. Describe what this PR did | |||
### Ⅱ. Does this pull request fix one issue? | |||
### Ⅲ. Why don't you add test cases (unit test/integration test)? | |||
### Ⅳ. Describe how to verify it | |||
### Ⅴ. Special notes for reviews |
@@ -1,71 +0,0 @@ | |||
# | |||
# Licensed to the Apache Software Foundation (ASF) under one or more | |||
# contributor license agreements. See the NOTICE file distributed with | |||
# this work for additional information regarding copyright ownership. | |||
# The ASF licenses this file to You under the Apache License, Version 2.0 | |||
# (the "License"); you may not use this file except in compliance with | |||
# the License. You may obtain a copy of the License at | |||
# | |||
# http://www.apache.org/licenses/LICENSE-2.0 | |||
# | |||
# Unless required by applicable law or agreed to in writing, software | |||
# distributed under the License is distributed on an "AS IS" BASIS, | |||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
# See the License for the specific language governing permissions and | |||
# limitations under the License. | |||
# | |||
coding: | |||
- 'pkg/**/*' | |||
- 'sample/**/*' | |||
- 'test/**/*' | |||
- 'cmd/**/*' | |||
# directory .github | |||
ci/cd: | |||
- any: ['.github/**/*'] | |||
# directory sample | |||
sample: | |||
- any: ['sample/**/*'] | |||
test: | |||
- any: ['test/**/*','testdata/**/*'] | |||
# directory cmd | |||
cmd: | |||
- any: ['cmd/**/*'] | |||
# directory changes | |||
milestone: | |||
- any: ['changes/**/*'] | |||
# directory pkg | |||
common: | |||
- any: ['pkg/common/**/*'] | |||
config: | |||
- any: ['pkg/config/**/*'] | |||
imports: | |||
- any: ['pkg/imports/**/*'] | |||
integration: | |||
- any: ['pkg/integration/**/*'] | |||
protocol: | |||
- any: ['pkg/protocol/**/*'] | |||
remoting: | |||
- any: ['pkg/remoting/**/*'] | |||
rm: | |||
- any: ['pkg/rm/**/*'] | |||
tc: | |||
- any: ['pkg/tc/**/*'] | |||
tm: | |||
- any: ['pkg/tm/**/*'] | |||
@@ -0,0 +1 @@ | |||
Subproject commit 6a895732124427993d93d4ccf93e2c664a9068cd |
@@ -1,155 +0,0 @@ | |||
name-template: '$RESOLVED_VERSION' | |||
tag-template: '$RESOLVED_VERSION' | |||
categories: | |||
- title: 'alignment/seata-java' | |||
labels: | |||
- 'alignment/seata-java' | |||
- title: 'bug' | |||
labels: | |||
- 'bug' | |||
- title: 'ci/cd' | |||
labels: | |||
- 'ci/cd' | |||
- title: 'coding' | |||
labels: | |||
- 'coding' | |||
- title: 'documentation' | |||
labels: | |||
- 'documentation' | |||
- title: 'enhancement' | |||
labels: | |||
- 'enhancement' | |||
- title: 'good first issue' | |||
labels: | |||
- 'good first issue' | |||
- title: 'integration' | |||
labels: | |||
- 'integration' | |||
- title: 'milestone' | |||
labels: | |||
- 'milestone' | |||
- title: 'module/at' | |||
labels: | |||
- 'module/at' | |||
- title: 'module/rm' | |||
labels: | |||
- 'module/rm' | |||
- title: 'module/saga' | |||
labels: | |||
- 'module/saga' | |||
- title: 'module/tcc' | |||
labels: | |||
- 'module/tcc' | |||
- title: 'module/tm' | |||
labels: | |||
- 'module/tm' | |||
- title: 'module/xa' | |||
labels: | |||
- 'module/xa' | |||
- title: 'optimise' | |||
labels: | |||
- 'optimise' | |||
- title: 'protocol' | |||
labels: | |||
- 'protocol' | |||
- title: 'question' | |||
labels: | |||
- 'question' | |||
- title: 'refactor' | |||
labels: | |||
- 'refactor' | |||
- title: 'remoting' | |||
labels: | |||
- 'remoting' | |||
- title: 'rm' | |||
labels: | |||
- 'rm' | |||
- title: 'task: help-wanted' | |||
labels: | |||
- 'task: help-wanted' | |||
- title: 'tm' | |||
labels: | |||
- 'tm' | |||
change-template: '- $TITLE (#$NUMBER)' | |||
change-title-escapes: '\<*_&' | |||
exclude-contributors: | |||
- dependabot | |||
- dependabot[bot] | |||
version-resolver: | |||
major: | |||
labels: | |||
- 'enhancement' | |||
- 'module/at' | |||
minor: | |||
labels: | |||
- 'enhancement' | |||
- 'module/saga' | |||
patch: | |||
labels: | |||
- 'bug' | |||
- 'documentation' | |||
- 'refactor' | |||
default: patch | |||
template: | | |||
$CHANGES | |||
**Full Changelog**: https://github.com/$OWNER/$REPOSITORY/compare/$PREVIOUS_TAG...v$RESOLVED_VERSION | |||
**Contributors**: $CONTRIBUTORS | |||
autolabeler: | |||
- label: 'documentation' | |||
files: | |||
- '*.md' | |||
- 'docs/**' | |||
title: | |||
- '/(docs?|typo|doc:|\[doc\]|comment)/i' | |||
- label: 'bug' | |||
title: | |||
- '/(fix|bug|error|fail|correct|missing)/i' | |||
- '/(race|deadlock)/i' | |||
- label: 'enhancement' | |||
title: | |||
- '/(feat|feature|add|implement|create)/i' | |||
- label: 'refactor' | |||
title: | |||
- '/(refactor|cleanup|deprecate|remove|unused)/i' | |||
- label: 'ci/cd' | |||
files: | |||
- '.github/workflows/**' | |||
title: | |||
- '/(ci|cd|workflow|pipeline)/i' | |||
- label: 'coding' | |||
title: | |||
- '/(bump|upgrade|dependencies?)/i' | |||
files: | |||
- 'go.mod' | |||
- 'go.sum' | |||
- label: 'question' | |||
title: | |||
- '/(question|ask|inquiry)/i' | |||
- label: 'good first issue' | |||
title: | |||
- '/(good first issue|easy|beginner|help wanted)/i' | |||
- label: 'module/saga' | |||
title: | |||
- '/(saga)/i' | |||
- label: 'module/at' | |||
title: | |||
- '/(at)/i' | |||
- label: 'module/xa' | |||
title: | |||
- '/(xa)/i' |
@@ -1,75 +0,0 @@ | |||
# | |||
# Licensed to the Apache Software Foundation (ASF) under one or more | |||
# contributor license agreements. See the NOTICE file distributed with | |||
# this work for additional information regarding copyright ownership. | |||
# The ASF licenses this file to You under the Apache License, Version 2.0 | |||
# (the "License"); you may not use this file except in compliance with | |||
# the License. You may obtain a copy of the License at | |||
# | |||
# http://www.apache.org/licenses/LICENSE-2.0 | |||
# | |||
# Unless required by applicable law or agreed to in writing, software | |||
# distributed under the License is distributed on an "AS IS" BASIS, | |||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
# See the License for the specific language governing permissions and | |||
# limitations under the License. | |||
# | |||
# This is a workflow to help you test the unit case and show codecov | |||
name: "build and codecov" | |||
on: | |||
push: | |||
branches: [ master ] | |||
pull_request: | |||
branches: ["*"] | |||
jobs: | |||
build: | |||
# The type of runner that the job will run on | |||
runs-on: ubuntu-latest | |||
strategy: | |||
matrix: | |||
golang: | |||
- 1.20 | |||
services: | |||
mysql: | |||
image: mysql:8.0 | |||
env: | |||
# The MySQL docker container requires these environment variables to be set | |||
# so we can create and migrate the test database. | |||
# See: https://hub.docker.com/_/mysql | |||
MYSQL_DATABASE: seata_go_test | |||
MYSQL_ROOT_PASSWORD: seata_go | |||
ports: | |||
- 3306:3306 | |||
options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3 | |||
steps: | |||
- name: "set up go" | |||
uses: actions/setup-go@v3 | |||
with: | |||
go-version: 1.20.14 | |||
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it | |||
- name: "checkout ${{ github.ref }}" | |||
uses: actions/checkout@v3 | |||
with: | |||
fetch-depth: 2 | |||
- name: "run go build" | |||
run: go build -v ./... | |||
- name: "run go test and out codecov" | |||
run: go test -v ./... -race -coverprofile=coverage.out -covermode=atomic | |||
- name: "upload coverage" | |||
uses: codecov/codecov-action@v4.0.1 | |||
with: | |||
token: ${{ secrets.CODECOV_TOKEN }} | |||
version: v0.6.0 | |||
env: | |||
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} |
@@ -1,69 +0,0 @@ | |||
# | |||
# Licensed to the Apache Software Foundation (ASF) under one or more | |||
# contributor license agreements. See the NOTICE file distributed with | |||
# this work for additional information regarding copyright ownership. | |||
# The ASF licenses this file to You under the Apache License, Version 2.0 | |||
# (the "License"); you may not use this file except in compliance with | |||
# the License. You may obtain a copy of the License at | |||
# | |||
# http://www.apache.org/licenses/LICENSE-2.0 | |||
# | |||
# Unless required by applicable law or agreed to in writing, software | |||
# distributed under the License is distributed on an "AS IS" BASIS, | |||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
# See the License for the specific language governing permissions and | |||
# limitations under the License. | |||
# | |||
# For most projects, this workflow file will not need changing; you simply need | |||
# to commit it to your repository. | |||
# | |||
# You may wish to alter this file to override the set of languages analyzed, | |||
# or to provide custom queries or build logic. | |||
# | |||
# ******** NOTE ******** | |||
# We have attempted to detect the languages in your repository. Please check | |||
# the `language` matrix defined below to confirm you have the correct set of | |||
# supported CodeQL languages. | |||
# | |||
name: CodeQL | |||
on: | |||
pull_request: | |||
# The branches below must be a subset of the branches above | |||
branches: "*" | |||
permissions: | |||
contents: read | |||
jobs: | |||
analyse: | |||
permissions: | |||
actions: read # for github/codeql-action/init to get workflow details | |||
contents: read # for actions/checkout to fetch code | |||
security-events: write # for github/codeql-action/autobuild to send a status report | |||
name: Analyse | |||
runs-on: ubuntu-latest | |||
steps: | |||
- name: Checkout repository | |||
uses: actions/checkout@v3 | |||
with: | |||
# We must fetch at least the immediate parents so that if this is | |||
# a pull request then we can checkout the head. | |||
fetch-depth: 2 | |||
# Initializes the CodeQL tools for scanning. | |||
- name: Initialize CodeQL | |||
uses: github/codeql-action/init@v2 | |||
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java). | |||
# If this step fails, then you should remove it and run the build manually (see below) | |||
- name: Autobuild | |||
uses: github/codeql-action/autobuild@v2 | |||
# Analysis | |||
- name: Perform CodeQL Analysis | |||
uses: github/codeql-action/analyze@v2 | |||
@@ -1,62 +0,0 @@ | |||
# | |||
# Licensed to the Apache Software Foundation (ASF) under one or more | |||
# contributor license agreements. See the NOTICE file distributed with | |||
# this work for additional information regarding copyright ownership. | |||
# The ASF licenses this file to You under the Apache License, Version 2.0 | |||
# (the "License"); you may not use this file except in compliance with | |||
# the License. You may obtain a copy of the License at | |||
# | |||
# http://www.apache.org/licenses/LICENSE-2.0 | |||
# | |||
# Unless required by applicable law or agreed to in writing, software | |||
# distributed under the License is distributed on an "AS IS" BASIS, | |||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
# See the License for the specific language governing permissions and | |||
# limitations under the License. | |||
# | |||
# This is a basic workflow to help you get started with Actions | |||
name: "golang ci lint" | |||
# Controls when the workflow will run | |||
on: | |||
# Triggers the workflow on push or pull request events but only for the master branch | |||
push: | |||
branches: [ master ] | |||
pull_request: | |||
branches: "*" | |||
# Allows you to run this workflow manually from the Actions tab | |||
# workflow_dispatch: | |||
# A workflow run is made up of one or more jobs that can run sequentially or in parallel | |||
jobs: | |||
# This workflow contains a single job called "build" | |||
build: | |||
# The type of runner that the job will run on | |||
runs-on: ubuntu-latest | |||
strategy: | |||
matrix: | |||
golang: | |||
- 1.20.0 | |||
# Steps represent a sequence of tasks that will be executed as part of the job | |||
steps: | |||
- name: "set up go" | |||
uses: actions/setup-go@v3 | |||
with: | |||
go-version: 1.20.0 | |||
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it | |||
- name: "checkout ${{ github.ref }}" | |||
uses: actions/checkout@v3 | |||
- name: "golang ci lint" | |||
uses: golangci/golangci-lint-action@v3.1.0 | |||
with: | |||
version: v1.51.0 | |||
args: --timeout=10m | |||
skip-go-installation: true | |||
skip-cache: true | |||
skip-pkg-cache: true |
@@ -1,83 +0,0 @@ | |||
# | |||
# Licensed to the Apache Software Foundation (ASF) under one or more | |||
# contributor license agreements. See the NOTICE file distributed with | |||
# this work for additional information regarding copyright ownership. | |||
# The ASF licenses this file to You under the Apache License, Version 2.0 | |||
# (the "License"); you may not use this file except in compliance with | |||
# the License. You may obtain a copy of the License at | |||
# | |||
# http://www.apache.org/licenses/LICENSE-2.0 | |||
# | |||
# Unless required by applicable law or agreed to in writing, software | |||
# distributed under the License is distributed on an "AS IS" BASIS, | |||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
# See the License for the specific language governing permissions and | |||
# limitations under the License. | |||
# | |||
name: "integrate-test" | |||
on: | |||
# Triggers the workflow on push or pull request events but only for the master branch | |||
push: | |||
branches: [ master ] | |||
pull_request: | |||
branches: "*" | |||
permissions: | |||
contents: read | |||
# A workflow run is made up of one or more jobs that can run sequentially or in parallel | |||
jobs: | |||
# This workflow contains a single job called "build" | |||
test: | |||
# The type of runner that the job will run on | |||
name: test | |||
runs-on: ubuntu-latest | |||
strategy: | |||
matrix: | |||
golang: | |||
- 1.20 | |||
steps: | |||
- name: "set up go" | |||
uses: actions/setup-go@v3 | |||
with: | |||
go-version: 1.20.0 | |||
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it | |||
- name: "checkout ${{ github.ref }}" | |||
uses: actions/checkout@v3 | |||
- name: Cache dependencies | |||
uses: actions/cache@v3 | |||
with: | |||
# Cache | |||
path: ~/go/pkg/mod | |||
# Cache key | |||
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} | |||
# An ordered list of keys to use for restoring the cache if no cache hit occurred for key | |||
restore-keys: | | |||
${{ runner.os }}-go- | |||
- name: Set up Docker | |||
uses: docker/setup-buildx-action@v2 | |||
- name: Install Docker Compose | |||
run: | | |||
curl -L "https://github.com/docker/compose/releases/download/v2.23.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose | |||
chmod +x /usr/local/bin/docker-compose | |||
docker-compose --version | |||
# This step only runs when the event type is a pull_request | |||
- name: Integrate Test | |||
if: ${{ github.event_name == 'pull_request' }} | |||
run: | | |||
chmod +x integrate_test.sh && [[ -n "${{github.event.pull_request.head.repo.full_name}}" ]] && [[ -n "${{github.event.pull_request.head.sha}}" ]] && [[ -n "${{github.base_ref}}" ]] && ./integrate_test.sh ${{github.event.pull_request.head.repo.full_name}} ${{github.event.pull_request.head.sha}} ${{github.base_ref}} | |||
# This step only runs when the event type is a push | |||
- name: Integrate Test | |||
if: ${{ github.event_name == 'push' }} | |||
run: | | |||
chmod +x integrate_test.sh && ./integrate_test.sh $GITHUB_REPOSITORY $GITHUB_SHA $GITHUB_BASE_REF |
@@ -1,42 +0,0 @@ | |||
# | |||
# Licensed to the Apache Software Foundation (ASF) under one or more | |||
# contributor license agreements. See the NOTICE file distributed with | |||
# this work for additional information regarding copyright ownership. | |||
# The ASF licenses this file to You under the Apache License, Version 2.0 | |||
# (the "License"); you may not use this file except in compliance with | |||
# the License. You may obtain a copy of the License at | |||
# | |||
# http://www.apache.org/licenses/LICENSE-2.0 | |||
# | |||
# Unless required by applicable law or agreed to in writing, software | |||
# distributed under the License is distributed on an "AS IS" BASIS, | |||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
# See the License for the specific language governing permissions and | |||
# limitations under the License. | |||
# | |||
# This workflow will help me to auto set up label for pull request | |||
name: "pull request labeler" | |||
on: | |||
- pull_request_target | |||
jobs: | |||
triage: | |||
permissions: | |||
contents: read | |||
pull-requests: write | |||
runs-on: ubuntu-latest | |||
steps: | |||
- name: "checkout ${{ github.ref }}" | |||
uses: actions/checkout@v3 | |||
with: | |||
persist-credentials: false | |||
submodules: true | |||
- name: "labeler" | |||
uses: actions/labeler@v4 | |||
with: | |||
repo-token: "${{ secrets.GITHUB_TOKEN }}" | |||
configuration-path: .github/actions/labeler/labeler.yml | |||
sync-labels: true |
@@ -1,71 +0,0 @@ | |||
# | |||
# Licensed to the Apache Software Foundation (ASF) under one or more | |||
# contributor license agreements. See the NOTICE file distributed with | |||
# this work for additional information regarding copyright ownership. | |||
# The ASF licenses this file to You under the Apache License, Version 2.0 | |||
# (the "License"); you may not use this file except in compliance with | |||
# the License. You may obtain a copy of the License at | |||
# | |||
# http://www.apache.org/licenses/LICENSE-2.0 | |||
# | |||
# Unless required by applicable law or agreed to in writing, software | |||
# distributed under the License is distributed on an "AS IS" BASIS, | |||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
# See the License for the specific language governing permissions and | |||
# limitations under the License. | |||
# | |||
name: License checker | |||
on: | |||
pull_request: | |||
branches: [ master ] | |||
schedule: | |||
- cron: "0 18 * * *" # TimeZone: UTC 0 | |||
jobs: | |||
license-header: | |||
name: License header | |||
runs-on: ubuntu-latest | |||
timeout-minutes: 10 | |||
steps: | |||
- uses: actions/checkout@v3 | |||
with: | |||
submodules: true | |||
- name: Check license header | |||
uses: apache/skywalking-eyes@985866ce7e324454f61e22eb2db2e998db09d6f3 | |||
with: | |||
log: info | |||
config: .licenserc.yaml | |||
mode: check | |||
dependency-license: | |||
name: Dependency licenses | |||
runs-on: ubuntu-latest | |||
timeout-minutes: 30 | |||
steps: | |||
- uses: actions/checkout@v3 | |||
with: | |||
submodules: true | |||
- name: Setup Go | |||
uses: actions/setup-go@v3 | |||
with: | |||
go-version: "1.20" | |||
- name: Check Dependencies Licenses | |||
run: | | |||
mkdir -p ./dist-material/ | |||
cp ./licenses/LICENSE.tpl ./dist-material/LICENSE.tpl | |||
go install github.com/apache/skywalking-eyes/cmd/license-eye@47febf5 | |||
license-eye dependency resolve --summary ./dist-material/LICENSE.tpl || exit 1 | |||
if [ -f "./dist-material/LICENSE)" ]; then | |||
echo "echo LICENSE check" | |||
cat ./dist-material/LICENSE | |||
fi | |||
- name: Check Dependencies Licenses Invalid | |||
run: | | |||
go install github.com/apache/skywalking-eyes/cmd/license-eye@47febf5 | |||
if [ ! -z "$(license-eye dependency check -v error | grep 'GPL\|LGPL\|ERROR')" ]; then | |||
echo "GPL or LGPL dependency LICENSE exists" | |||
license-eye dependency check -v error | grep 'GPL\|LGPL\|ERROR' | |||
exit 1 | |||
fi |
@@ -0,0 +1,63 @@ | |||
# This is a basic workflow to help you get started with Actions | |||
name: CI | |||
# Controls when the action will run. Triggers the workflow on push or pull request | |||
# events for all branches and tags | |||
on: | |||
push: | |||
branches: [ '**' ] | |||
pull_request: | |||
branches: [ '**' ] | |||
# A workflow run is made up of one or more jobs that can run sequentially or in parallel | |||
jobs: | |||
# This workflow contains a single job called "lint" | |||
lint-and-test: | |||
strategy: | |||
matrix: | |||
go-version: [ 1.15.x ] | |||
# The type of runner that the job will run on | |||
runs-on: ubuntu-latest | |||
# Steps represent a sequence of tasks that will be executed as part of the job | |||
steps: | |||
- name: Set up Go | |||
uses: actions/setup-go@v2 | |||
with: | |||
go-version: ${{ matrix.go-version }} | |||
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it | |||
- name: Checkout code | |||
uses: actions/checkout@v2 | |||
- name: Go Build | |||
run: | | |||
go build ./... | |||
- name: Go Vet | |||
run: | | |||
go vet -v ./... | |||
- name: GolangCI Lint | |||
run: | | |||
curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.39.0 | |||
golangci-lint run ./... | |||
- name: Unit Tests | |||
run: | | |||
mkdir -p build | |||
go test ./... -coverprofile=./build/c.out | |||
- name: Code Coverage | |||
run: | | |||
go get github.com/axw/gocov/gocov | |||
go get github.com/AlekSi/gocov-xml | |||
go tool cover -html=build/c.out -o build/coverage.html | |||
gocov convert build/c.out | gocov-xml > build/coverage.xml | |||
- name: Archive code coverage results | |||
uses: actions/upload-artifact@v2 | |||
with: | |||
name: code-coverage-report | |||
path: build/ |
@@ -1,23 +0,0 @@ | |||
name: Release Drafter | |||
on: | |||
push: | |||
branches: | |||
- unstable | |||
pull_request_target: | |||
types: [ opened, reopened, synchronize ] | |||
permissions: | |||
contents: write | |||
pull-requests: write | |||
jobs: | |||
update_release_draft: | |||
permissions: | |||
contents: write | |||
pull-requests: write | |||
runs-on: ubuntu-latest | |||
steps: | |||
- uses: release-drafter/release-drafter@v6 | |||
env: | |||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} |
@@ -0,0 +1,53 @@ | |||
name: Release | |||
on: | |||
release: | |||
types: [created] | |||
jobs: | |||
releases-matrix: | |||
name: Release Go Binary | |||
runs-on: ubuntu-latest | |||
strategy: | |||
matrix: | |||
# build and publish in parallel: linux/386, linux/amd64, windows/386, windows/amd64, darwin/amd64 | |||
goos: [linux, windows] | |||
goarch: ["386", amd64, arm] | |||
exclude: | |||
- goarch: "arm" | |||
goos: windows | |||
steps: | |||
- uses: actions/checkout@v2 | |||
- uses: wangyoucao577/go-release-action@v1.18 | |||
with: | |||
github_token: ${{ secrets.GITHUB_TOKEN }} | |||
goos: ${{ matrix.goos }} | |||
goarch: ${{ matrix.goarch }} | |||
goversion: "https://golang.org/dl/go1.15.linux-amd64.tar.gz" | |||
project_path: "./cmd/tc/" | |||
binary_name: "seata-golang" | |||
docker-build: | |||
strategy: | |||
matrix: | |||
go-version: [ 1.15.x ] | |||
# The type of runner that the job will run on | |||
runs-on: ubuntu-latest | |||
steps: | |||
- name: Docker Build | |||
if: ${{ github.ref == 'refs/heads/master' || github.ref == 'refs/heads/v2' || contains(github.ref, 'release') }} | |||
env: | |||
DOCKER_USERNAME: ${{ secrets.REGISTRY_USERNAME }} | |||
run: | | |||
go mod tidy | |||
REGISTRY=$DOCKER_USERNAME make build-images | |||
- name: Push | |||
if: ${{ github.ref == 'refs/heads/master' || github.ref == 'refs/heads/v2' || contains(github.ref, 'release') }} | |||
env: | |||
DOCKER_USERNAME: ${{ secrets.REGISTRY_USERNAME }} | |||
DOCKER_PASSWORD: ${{ secrets.REGISTRY_PASSWORD }} | |||
COMMIT: ${{ github.sha }} | |||
run: | | |||
echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin | |||
REGISTRY=$DOCKER_USERNAME make push |
@@ -0,0 +1,35 @@ | |||
# | |||
# Licensed to the Apache Software Foundation (ASF) under one | |||
# or more contributor license agreements. See the NOTICE file | |||
# distributed with this work for additional information | |||
# regarding copyright ownership. The ASF licenses this file | |||
# to you under the Apache License, Version 2.0 (the | |||
# "License"); you may not use this file except in compliance | |||
# with the License. You may obtain a copy of the License at | |||
# | |||
# http://www.apache.org/licenses/LICENSE-2.0 | |||
# | |||
# Unless required by applicable law or agreed to in writing, | |||
# software distributed under the License is distributed on an | |||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | |||
# KIND, either express or implied. See the License for the | |||
# specific language governing permissions and limitations | |||
# under the License. | |||
# | |||
name: reviewdog | |||
on: [pull_request] | |||
jobs: | |||
golangci-lint: | |||
name: review | |||
runs-on: ubuntu-latest | |||
steps: | |||
- name: Check out code into the Go module directory | |||
uses: actions/checkout@v2 | |||
with: | |||
persist-credentials: false | |||
submodules: true | |||
- name: golangci-lint | |||
uses: ./.github/actions/review-dog | |||
with: | |||
golangci_lint_flags: "--timeout=10m" |
@@ -1,50 +0,0 @@ | |||
# | |||
# Licensed to the Apache Software Foundation (ASF) under one or more | |||
# contributor license agreements. See the NOTICE file distributed with | |||
# this work for additional information regarding copyright ownership. | |||
# The ASF licenses this file to You under the Apache License, Version 2.0 | |||
# (the "License"); you may not use this file except in compliance with | |||
# the License. You may obtain a copy of the License at | |||
# | |||
# http://www.apache.org/licenses/LICENSE-2.0 | |||
# | |||
# Unless required by applicable law or agreed to in writing, software | |||
# distributed under the License is distributed on an "AS IS" BASIS, | |||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
# See the License for the specific language governing permissions and | |||
# limitations under the License. | |||
# | |||
# https://github.com/actions/stale | |||
name: 'close the stale content' | |||
on: | |||
schedule: | |||
- cron: '0 0 * * *' | |||
permissions: | |||
pull-requests: write | |||
issues: write | |||
jobs: | |||
stale: | |||
runs-on: ubuntu-latest | |||
steps: | |||
- uses: actions/stale@v4 | |||
with: | |||
#never automatically stale issues | |||
days-before-issue-stale: -1 | |||
#never automatically close issues | |||
days-before-issue-close: -1 | |||
exempt-issue-labels: 'feature' | |||
stale-issue-message: > | |||
This issue has not been active for the past 4 weeks, so we will automatically close this issue after 7 days | |||
close-issue-message: > | |||
This issue has not been active for the past 5 weeks, so we are closing it now | |||
#never automatically stale pr | |||
days-before-pr-stale: -1 | |||
#never automatically close pr | |||
days-before-pr-close: -1 | |||
stale-pr-message: > | |||
This PR has not been active for the past 12 weeks, so we will automatically close this issue after seven days | |||
close-pr-message: > | |||
This PR has not had any activity for the past 13 weeks, so we are now closing it down |
@@ -1,23 +1,3 @@ | |||
# | |||
# Licensed to the Apache Software Foundation (ASF) under one or more | |||
# contributor license agreements. See the NOTICE file distributed with | |||
# this work for additional information regarding copyright ownership. | |||
# The ASF licenses this file to You under the Apache License, Version 2.0 | |||
# (the "License"); you may not use this file except in compliance with | |||
# the License. You may obtain a copy of the License at | |||
# | |||
# http://www.apache.org/licenses/LICENSE-2.0 | |||
# | |||
# Unless required by applicable law or agreed to in writing, software | |||
# distributed under the License is distributed on an "AS IS" BASIS, | |||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
# See the License for the specific language governing permissions and | |||
# limitations under the License. | |||
# | |||
# Idea configuration file | |||
.idea/ | |||
# Binaries for programs and plugins | |||
*.exe | |||
*.exe~ | |||
@@ -31,11 +11,14 @@ | |||
# Output of the go coverage tool, specifically when used with LiteIDE | |||
*.out | |||
# build products | |||
dist/ | |||
# Dependency directories (remove the comment below to include it) | |||
# vendor/ | |||
.vscode | |||
.codecc | |||
vendor | |||
.idea/ | |||
vendor/ | |||
root.data | |||
root.data.1 | |||
trace.out | |||
cmd/tc/cmd | |||
cmd/tc/tc | |||
cmd/tc/trace.out | |||
dist/tc |
@@ -0,0 +1,3 @@ | |||
[submodule ".github/actions/review-dog"] | |||
path = .github/actions/review-dog | |||
url = git@github.com:reviewdog/action-golangci-lint.git |
@@ -1,92 +1,18 @@ | |||
# | |||
# Licensed to the Apache Software Foundation (ASF) under one or more | |||
# contributor license agreements. See the NOTICE file distributed with | |||
# this work for additional information regarding copyright ownership. | |||
# The ASF licenses this file to You under the Apache License, Version 2.0 | |||
# (the "License"); you may not use this file except in compliance with | |||
# the License. You may obtain a copy of the License at | |||
# | |||
# http://www.apache.org/licenses/LICENSE-2.0 | |||
# | |||
# Unless required by applicable law or agreed to in writing, software | |||
# distributed under the License is distributed on an "AS IS" BASIS, | |||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
# See the License for the specific language governing permissions and | |||
# limitations under the License. | |||
# | |||
linters-settings: | |||
govet: | |||
shadow: true | |||
golint: | |||
min-confidence: 0 | |||
gocyclo: | |||
min-complexity: 10 | |||
maligned: | |||
suggest-new: true | |||
dupl: | |||
threshold: 100 | |||
goconst: | |||
min-len: 2 | |||
min-occurrences: 2 | |||
depguard: | |||
list-type: blacklist | |||
packages: | |||
# logging is allowed only by logutils.Log, logrus | |||
# is allowed to use only in logutils package | |||
- github.com/sirupsen/logrus | |||
misspell: | |||
locale: US | |||
lll: | |||
line-length: 140 | |||
goimports: | |||
local-prefixes: github.com/golangci/golangci-lint | |||
gocritic: | |||
enabled-tags: | |||
- performance | |||
- style | |||
- experimental | |||
disabled-checks: | |||
- wrapperFunc | |||
run: | |||
deadline: 5m | |||
linters: | |||
disable-all: true | |||
enable: | |||
- deadcode | |||
- errcheck | |||
- gosimple | |||
- govet | |||
- staticcheck | |||
- ineffassign | |||
- misspell | |||
- asciicheck | |||
- bodyclose | |||
- rowserrcheck | |||
- gofmt | |||
- durationcheck | |||
- sqlclosecheck | |||
run: | |||
issues: | |||
exclude-dirs: | |||
- test/testdata_etc | |||
- pkg/golinters/goanalysis/(checker|passes) | |||
exclude-rules: | |||
- text: "weak cryptographic primitive" | |||
linters: | |||
- gosec | |||
- linters: | |||
- staticcheck | |||
text: "SA1019:" | |||
- path: _test\.go | |||
linters: | |||
- errcheck | |||
- gosec | |||
- rowserrcheck | |||
- govet | |||
# golangci.com configuration | |||
# https://github.com/golangci/golangci/wiki/Configuration | |||
service: | |||
golangci-lint-version: 1.57.x # use the fixed version to not introduce new linters unexpectedly | |||
prepare: | |||
- echo "here I can run custom commands, but no preparation needed for this repo" | |||
- staticcheck | |||
- structcheck | |||
- typecheck | |||
- varcheck | |||
- goimports | |||
- gocritic | |||
- revive |
@@ -1,78 +0,0 @@ | |||
# | |||
# Licensed to the Apache Software Foundation (ASF) under one or more | |||
# contributor license agreements. See the NOTICE file distributed with | |||
# this work for additional information regarding copyright ownership. | |||
# The ASF licenses this file to You under the Apache License, Version 2.0 | |||
# (the "License"); you may not use this file except in compliance with | |||
# the License. You may obtain a copy of the License at | |||
# | |||
# http://www.apache.org/licenses/LICENSE-2.0 | |||
# | |||
# Unless required by applicable law or agreed to in writing, software | |||
# distributed under the License is distributed on an "AS IS" BASIS, | |||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
# See the License for the specific language governing permissions and | |||
# limitations under the License. | |||
# | |||
header: # `header` section is configurations for source codes license header. | |||
license: | |||
spdx-id: Apache-2.0 # the spdx id of the license, it's convenient when your license is standard SPDX license. | |||
copyright-owner: Apache Software Foundation # the copyright owner to replace the [owner] in the `spdx-id` template. | |||
content: | # `license` will be used as the content when `fix` command needs to insert a license header. | |||
Licensed to the Apache Software Foundation (ASF) under one or more | |||
contributor license agreements. See the NOTICE file distributed with | |||
this work for additional information regarding copyright ownership. | |||
The ASF licenses this file to You under the Apache License, Version 2.0 | |||
(the "License"); you may not use this file except in compliance with | |||
the License. You may obtain a copy of the License at | |||
http://www.apache.org/licenses/LICENSE-2.0 | |||
Unless required by applicable law or agreed to in writing, software | |||
distributed under the License is distributed on an "AS IS" BASIS, | |||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
See the License for the specific language governing permissions and | |||
limitations under the License. | |||
# `pattern` is optional regexp if all the file headers are the same as `license` or the license of `spdx-id` and `copyright-owner`. | |||
pattern: | | |||
Licensed to the Apache Software Foundation under one or more contributor | |||
license agreements. See the NOTICE file distributed with | |||
this work for additional information regarding copyright | |||
ownership. The Apache Software Foundation licenses this file to you under | |||
the Apache License, Version 2.0 \(the "License"\); you may | |||
not use this file except in compliance with the License. | |||
You may obtain a copy of the License at | |||
http://www.apache.org/licenses/LICENSE-2.0 | |||
Unless required by applicable law or agreed to in writing, | |||
software distributed under the License is distributed on an | |||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | |||
KIND, either express or implied. See the License for the | |||
specific language governing permissions and limitations | |||
under the License. | |||
paths: # `paths` are the path list that will be checked (and fixed) by license-eye, default is ['**']. | |||
- '**' | |||
paths-ignore: # `paths-ignore` are the path list that will be ignored by license-eye. | |||
- 'licenses' | |||
- '**/go.mod' | |||
- '**/go.sum' | |||
- 'LICENSE' | |||
- 'DISCLAIMER' | |||
- 'NOTICE' | |||
- '.github' | |||
comment: on-failure # on what condition license-eye will comment on the pull request, `on-failure`, `always`, `never`. | |||
language: | |||
Go: | |||
extensions: | |||
- ".go" | |||
comment_style_id: SlashAsterisk | |||
# license-location-threshold specifies the index threshold where the license header can be located, | |||
# after all, a "header" cannot be TOO far from the file start. | |||
license-location-threshold: 80 | |||
dependency: | |||
files: | |||
- go.mod |
@@ -1,24 +0,0 @@ | |||
# | |||
# Licensed to the Apache Software Foundation (ASF) under one or more | |||
# contributor license agreements. See the NOTICE file distributed with | |||
# this work for additional information regarding copyright ownership. | |||
# The ASF licenses this file to You under the Apache License, Version 2.0 | |||
# (the "License"); you may not use this file except in compliance with | |||
# the License. You may obtain a copy of the License at | |||
# | |||
# http://www.apache.org/licenses/LICENSE-2.0 | |||
# | |||
# Unless required by applicable law or agreed to in writing, software | |||
# distributed under the License is distributed on an "AS IS" BASIS, | |||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
# See the License for the specific language governing permissions and | |||
# limitations under the License. | |||
# | |||
# See https://pre-commit.com for more information | |||
# See https://pre-commit.com/hooks.html for more hooks | |||
repos: | |||
- repo: http://github.com/golangci/golangci-lint | |||
rev: v1.42.1 | |||
hooks: | |||
- id: golangci-lint |
@@ -0,0 +1,6 @@ | |||
runner: | |||
golint: | |||
cmd: golangci-lint run | |||
errorformat: | |||
- "%f:%l:%c: %m" | |||
level: warning |
@@ -1,212 +0,0 @@ | |||
<!-- | |||
Licensed to the Apache Software Foundation (ASF) under one or more | |||
contributor license agreements. See the NOTICE file distributed with | |||
this work for additional information regarding copyright ownership. | |||
The ASF licenses this file to You under the Apache License, Version 2.0 | |||
(the "License"); you may not use this file except in compliance with | |||
the License. You may obtain a copy of the License at | |||
http://www.apache.org/licenses/LICENSE-2.0 | |||
Unless required by applicable law or agreed to in writing, software | |||
distributed under the License is distributed on an "AS IS" BASIS, | |||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
See the License for the specific language governing permissions and | |||
limitations under the License. | |||
--> | |||
# Contributing to seata-go | |||
It is warmly welcomed if you have interest to hack on seata-go. First, we encourage this kind of willing very much. And here is a list of contributing guide for you. | |||
[[中文贡献文档](./CONTRIBUTING_CN.md)] | |||
## Topics | |||
* [Reporting general issues](#reporting-general-issues) | |||
* [Code and doc contribution](#code-and-doc-contribution) | |||
* [Test case contribution](#test-case-contribution) | |||
* [Engage to help anything](#engage-to-help-anything) | |||
* [Code Style](#code-style) | |||
## Reporting general issues | |||
To be honest, we regard every user of seata-go as a very kind contributor. After experiencing seata-go, you may have some feedback for the project. Then feel free to open an issue via [NEW ISSUE](https://github.com/apache/incubator-seata-go/issues/new/choose). | |||
Since we collaborate project seata-go in a distributed way, we appreciate **WELL-WRITTEN**, **DETAILED**, **EXPLICIT** issue reports. To make the communication more efficient, we wish everyone could search if your issue is an existing one in the searching list. If you find it existing, please add your details in comments under the existing issue instead of opening a brand new one. | |||
To make the issue details as standard as possible, we setup an [ISSUE TEMPLATE](./.github/ISSUE_TEMPLATE) for issue reporters. Please **BE SURE** to follow the instructions to fill fields in template. | |||
There are a lot of cases when you could open an issue: | |||
* bug report | |||
* feature request | |||
* performance issues | |||
* feature proposal | |||
* feature design | |||
* help wanted | |||
* doc incomplete | |||
* test improvement | |||
* any questions on project | |||
* and so on | |||
Also we must remind that when filling a new issue, please remember to remove the sensitive data from your post. Sensitive data could be password, secret key, network locations, private business data and so on. | |||
## Code and doc contribution | |||
Every action to make project seata-go better is encouraged. On GitHub, every improvement for seata-go could be via a PR (short for pull request). | |||
* If you find a typo, try to fix it! | |||
* If you find a bug, try to fix it! | |||
* If you find some redundant codes, try to remove them! | |||
* If you find some test cases missing, try to add them! | |||
* If you could enhance a feature, please **DO NOT** hesitate! | |||
* If you find code implicit, try to add comments to make it clear! | |||
* If you find code ugly, try to refactor that! | |||
* If you can help to improve documents, it could not be better! | |||
* If you find document incorrect, just do it and fix that! | |||
* ... | |||
Actually it is impossible to list them completely. Just remember one principle: | |||
> WE ARE LOOKING FORWARD TO ANY PR FROM YOU. | |||
Since you are ready to improve seata-go with a PR, we suggest you could take a look at the PR rules here. | |||
* [Workspace Preparation](#workspace-preparation) | |||
* [Branch Definition](#branch-definition) | |||
* [Commit Rules](#commit-rules) | |||
* [PR Description](#pr-description) | |||
### Workspace Preparation | |||
To put forward a PR, we assume you have registered a GitHub ID. Then you could finish the preparation in the following steps: | |||
1. **FORK** seata-go to your repository. To make this work, you just need to click the button Fork in right-left of [seata/seata](https://github.com/apache/incubator-seata-go) main page. Then you will end up with your repository in `https://github.com/<your-username>/seata-go`, in which `your-username` is your GitHub username. | |||
1. **CLONE** your own repository to develop locally. Use `git clone git@github.com:<your-username>/seata-go.git` to clone repository to your local machine. Then you can create new branches to finish the change you wish to make. | |||
1. **Set Remote** upstream to be `git@github.com:apache/seata-go.git` using the following two commands: | |||
```bash | |||
git remote add upstream git@github.com:apache/seata-go.git | |||
git remote set-url --push upstream no-pushing | |||
``` | |||
With this remote setting, you can check your git remote configuration like this: | |||
```shell | |||
$ git remote -v | |||
origin git@github.com:<your-username>/seata-go.git (fetch) | |||
origin git@github.com:<your-username>/seata-go.git (push) | |||
upstream git@github.com:apache/seata-go.git (fetch) | |||
upstream no-pushing (push) | |||
``` | |||
Adding this, we can easily synchronize local branches with upstream branches. | |||
### Branch Definition | |||
Right now we assume every contribution via pull request is for [branch develop](https://github.com/apache/incubator-seata-go/tree/master) in seata-go. Before contributing, be aware of branch definition would help a lot. | |||
As a contributor, keep in mind again that every contribution via pull request is for branch develop. While in project seata-go, there are several other branches, we generally call them release branches(such as 0.6.0,0.6.1), feature branches, hotfix branches and master branch. | |||
When officially releasing a version, there will be a release branch and named with the version number. | |||
After the release, we will merge the commit of the release branch into the master branch. | |||
When we find that there is a bug in a certain version, we will decide to fix it in a later version or fix it in a specific hotfix version. When we decide to fix the hotfix version, we will checkout the hotfix branch based on the corresponding release branch, perform code repair and verification, and merge it into the develop branch and the master branch. | |||
For larger features, we will pull out the feature branch for development and verification. | |||
### Commit Rules | |||
Actually in seata-go, we take two rules serious when committing: | |||
* [Commit Message](#commit-message) | |||
* [Commit Content](#commit-content) | |||
#### Commit Message | |||
Commit message could help reviewers better understand what is the purpose of submitted PR. It could help accelerate the code review procedure as well. We encourage contributors to use **EXPLICIT** commit message rather than ambiguous message. In general, we advocate the following commit message type: | |||
* docs: xxxx. For example, "docs: add docs about seata-go cluster installation". | |||
* feature: xxxx.For example, "feature: support oracle in AT mode". | |||
* bugfix: xxxx. For example, "bugfix: fix panic when input nil parameter". | |||
* optimize: xxxx. For example, "optimize: simplify to make codes more readable". | |||
* test: xxx. For example, "test: add unit test case for func InsertIntoArray". | |||
* other readable and explicit expression ways. | |||
On the other side, we discourage contributors from committing message like the following ways: | |||
* ~~fix bug~~ | |||
* ~~update~~ | |||
* ~~add doc~~ | |||
If you get lost, please see [How to Write a Git Commit Message](http://chris.beams.io/posts/git-commit/) for a start. | |||
#### Commit Content | |||
Commit content represents all content changes included in one commit. We had better include things in one single commit which could support reviewer's complete review without any other commits' help. In another word, contents in one single commit can pass the CI to avoid code mess. In brief, there are three minor rules for us to keep in mind: | |||
* avoid very large change in a commit; | |||
* complete and reviewable for each commit. | |||
* check git config(`user.name`, `user.email`) when committing to ensure that it is associated with your GitHub ID. | |||
```bash | |||
git config --get user.name | |||
git config --get user.email | |||
``` | |||
* when submitting pr, please add a brief description of the current changes to the dev.md file under the 'changes/' folder | |||
In addition, in the code change part, we suggest that all contributors should read the [code style of seata-go](#code-style). | |||
No matter commit message, or commit content, we do take more emphasis on code review. | |||
#### Format your code | |||
Before submitting the code, execute the script of formatting the code under the project root directory: | |||
~~~shell | |||
sh goimports.sh | |||
~~~ | |||
### PR Description | |||
PR is the only way to make change to seata-go project files. To help reviewers better get your purpose, PR description could not be too detailed. We encourage contributors to follow the [PR template](./.github/pull-request-template.md) to finish the pull request. | |||
## Test case contribution | |||
Any test case will be welcomed. Currently, seata-go functional test cases are of high priority. | |||
- For unit tests, create a XXX_test.go file in the file directory of go file | |||
## Engage to help anything | |||
We choose GitHub as the primary place for seata-go to collaborate. So the latest updates of seata-go are always here. Although contributions via PR is an explicit way to help, we still call for any other ways. | |||
* reply to other's issues if you could; | |||
* help solve other user's problems; | |||
* help review other's PR design; | |||
* help review other's codes in PR; | |||
* discuss about seata-go to make things clearer; | |||
* advocate seata-go technology beyond GitHub; | |||
* write blogs on seata-go and so on. | |||
## Code Style | |||
Seata-go code style reference [uber-go/guide](https://github.com/uber-go/guide) 。 | |||
### IDE Plugin Install(not necessary) | |||
*It is not necessary to install, if you want to find a problem when you are coding.* | |||
install go fmt 和 goimports plugin,detailed reference:https://github.com/golang/tools | |||
In a word, **ANY HELP IS CONTRIBUTION.** |
@@ -1,210 +0,0 @@ | |||
<!-- | |||
Licensed to the Apache Software Foundation (ASF) under one or more | |||
contributor license agreements. See the NOTICE file distributed with | |||
this work for additional information regarding copyright ownership. | |||
The ASF licenses this file to You under the Apache License, Version 2.0 | |||
(the "License"); you may not use this file except in compliance with | |||
the License. You may obtain a copy of the License at | |||
http://www.apache.org/licenses/LICENSE-2.0 | |||
Unless required by applicable law or agreed to in writing, software | |||
distributed under the License is distributed on an "AS IS" BASIS, | |||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
See the License for the specific language governing permissions and | |||
limitations under the License. | |||
--> | |||
# 为 seata-go 做贡献 | |||
如果你有兴趣为 seata-go 贡献代码,我们会热烈欢迎。首先,我们非常鼓励这种意愿。这是为您提供的贡献指南列表。 | |||
[[English Contributing Document](./CONTRIBUTING.md)] | |||
## 话题 | |||
* [报告一般问题](#报告一般问题) | |||
* [代码和文档贡献](#代码和文档贡献) | |||
* [测试用例贡献](#测试用例贡献) | |||
* [参与帮助任何事情](#参与帮助任何事情) | |||
* [代码风格](#代码风格) | |||
## 报告一般问题 | |||
老实说我们把每一个 seata-go 用户都视为非常善良的贡献者。在体验了 seata-go 之后,您可能会对项目有一些反馈。然后随时通过 [NEW ISSUE](https://github.com/apache/incubator-seata-go/issues/new/choose)打开一个问题。 | |||
因为我们在一个分布式的方式合作项目 seata-go,我们欣赏写得很好的,详细的,准确的问题报告。为了让沟通更高效,我们希望每个人都可以搜索您的问题是否在搜索列表中。如果您发现它存在,请在现有问题下的评论中添加您的详细信息,而不是打开一个全新的问题。 | |||
为了使问题细节尽可能标准,我们为问题报告者设置了一个[问题模板](./.github/ISSUE_TEMPLATE) 请务必按照说明填写模板中的字段。 | |||
有很多情况你可以打开一个问题: | |||
* 错误报告 | |||
* 功能要求 | |||
* 性能问题 | |||
* 功能提案 | |||
* 功能设计 | |||
* 需要帮助 | |||
* 文档不完整 | |||
* 测试改进 | |||
* 关于项目的任何问题 | |||
* 等等 | |||
另外我们必须提醒的是,在填写新问题时,请记住从您的帖子中删除敏感数据。敏感数据可能是密码、密钥、网络位置、私人业务数据等。 | |||
## 代码和文档贡献 | |||
鼓励采取一切措施使 seata-go 项目变得更好。在 GitHub 上,seata-go 的每项改进都可以通过 PR(Pull Request 的缩写)实现。 | |||
* 如果您发现错别字,请尝试修复它! | |||
* 如果您发现错误,请尝试修复它! | |||
* 如果您发现一些多余的代码,请尝试删除它们! | |||
* 如果您发现缺少一些测试用例,请尝试添加它们! | |||
* 如果您可以增强功能,请**不要**犹豫! | |||
* 如果您发现代码晦涩难懂,请尝试添加注释以使其更加易读! | |||
* 如果您发现代码丑陋,请尝试重构它! | |||
* 如果您能帮助改进文档,那就再好不过了! | |||
* 如果您发现文档不正确,只需执行并修复它! | |||
* ... | |||
实际上不可能完整地列出它们。记住一个原则: | |||
> 我们期待您的任何PR。 | |||
由于您已准备好通过 PR 改进 seata-go,我们建议您可以在此处查看 PR 规则。 | |||
* [工作区准备](#工作区准备) | |||
* [分支定义](#分支定义) | |||
* [提交规则](#提交规则) | |||
* [PR说明](#PR说明) | |||
### 工作区准备 | |||
为了提出 PR,我们假设你已经注册了一个 GitHub ID。然后您可以通过以下步骤完成准备工作: | |||
1. **FORK** seata-go 到您的存储库。要完成这项工作,您只需单击 [apache/seata-go](https://github.com/apache/incubator-seata-go) 主页右侧的 Fork 按钮。然后你将在 中得到你的存储库`https://github.com/<your-username>/seata-go`,其中 your-username 是你的 GitHub 用户名。 | |||
2. **克隆** 您自己的存储库以在本地开发. 用于 `git clone git@github.com:<your-username>/seata-go.git` 将存储库克隆到本地计算机。 然后您可以创建新分支来完成您希望进行的更改。 | |||
3. **设置远程** 将上游设置为 `git@github.com:apache/seata-go.git` 使用以下两个命令: | |||
```bash | |||
git remote add upstream git@github.com:apache/seata-go.git | |||
git remote set-url --push upstream no-pushing | |||
``` | |||
使用此远程设置,您可以像这样检查您的 git 远程配置: | |||
```shell | |||
$ git remote -v | |||
origin git@github.com:<your-username>/seata-go.git (fetch) | |||
origin git@github.com:<your-username>/seata-go.git (push) | |||
upstream git@github.com:apache/seata-go.git (fetch) | |||
upstream no-pushing (push) | |||
``` | |||
添加这个,我们可以轻松地将本地分支与上游分支同步。 | |||
### 分支定义 | |||
现在我们假设通过拉取请求的每个贡献都是针对 seata-go 中的 [开发分支](https://github.com/apache/incubator-seata-go/tree/master) 。在贡献之前,请注意分支定义会很有帮助。 | |||
作为贡献者,请再次记住,通过拉取请求的每个贡献都是针对分支开发的。而在 seata-go 项目中,还有其他几个分支,我们一般称它们为 release 分支(如0.6.0、0.6.1)、feature 分支、hotfix 分支和 master 分支。 | |||
当正式发布一个版本时,会有一个发布分支并以版本号命名。 | |||
在发布之后,我们会将发布分支的提交合并到主分支中。 | |||
当我们发现某个版本有 bug 时,我们会决定在以后的版本中修复它,或者在特定的 hotfix 版本中修复它。当我们决定修复 hotfix 版本时,我们会根据对应的 release 分支 checkout hotfix 分支,进行代码修复和验证,合并到 develop 分支和 master 分支。 | |||
对于较大的功能,我们将拉出功能分支进行开发和验证。 | |||
### 提交规则 | |||
实际上,在 seata-go 中,我们在提交时会认真对待两条规则: | |||
* [提交消息](#提交消息) | |||
* [提交内容](#提交内容) | |||
#### 提交消息 | |||
提交消息可以帮助审稿人更好地理解提交 PR 的目的是什么。它还可以帮助加快代码审查过程。我们鼓励贡献者使用显式的提交信息,而不是模糊的信息。一般来说,我们提倡以下提交消息类型: | |||
* docs: xxxx. For example, "docs: add docs about seata-go cluster installation". | |||
* feature: xxxx.For example, "feature: support oracle in AT mode". | |||
* bugfix: xxxx. For example, "bugfix: fix panic when input nil parameter". | |||
* optimize: xxxx. For example, "optimize: simplify to make codes more readable". | |||
* test: xxx. For example, "test: add unit test case for func InsertIntoArray". | |||
* 其他可读和显式的表达方式。 | |||
另一方面,我们不鼓励贡献者通过以下方式提交消息: | |||
* ~~修复错误~~ | |||
* ~~更新~~ | |||
* ~~添加文档~~ | |||
如果你不知道该怎么做,请参阅 [如何编写 Git 提交消息](http://chris.beams.io/posts/git-commit/) 作为开始。 | |||
#### 提交内容 | |||
提交内容表示一次提交中包含的所有内容更改。我们最好在一次提交中包含可以支持审阅者完整审查的内容,而无需任何其他提交的帮助。换句话说,一次提交中的内容可以通过 CI 以避免代码混乱。简而言之,我们需要牢记三个小规则: | |||
* 避免在提交中进行非常大的更改; | |||
* 每次提交都完整且可审查。 | |||
* 提交时检查 git config(`user.name`, `user.email`) 以确保它与您的 GitHub ID 相关联。 | |||
```bash | |||
git config --get user.name | |||
git config --get user.email | |||
``` | |||
* 提交pr时,请在'changes/'文件夹下的dev.md文件中添加当前更改的简要说明 | |||
另外,在代码变更部分,我们建议所有贡献者阅读 seata-go 的 [代码风格](#代码风格)。 | |||
无论是提交信息,还是提交内容,我们都更加重视代码审查。 | |||
#### 格式化代码 | |||
提交代码之前,在项目根目录下执行格式化代码的脚本: | |||
~~~shell | |||
sh goimports.sh | |||
~~~ | |||
### PR说明 | |||
PR 是更改 seata-go 项目文件的唯一方法。为了帮助审查人更好地理解你的目的,PR 描述不能太详细。我们鼓励贡献者遵循 [PR 模板](./.github/PULL_REQUEST_TEMPLATE.md) 来完成拉取请求。 | |||
## 测试用例贡献 | |||
任何测试用例都会受到欢迎。目前,seata-go 功能测试用例是高优先级的。 | |||
* 对于单元测试,在文件目录下创建一个 xxx_test.go 文件即可 | |||
## 参与帮助任何事情 | |||
我们选择 GitHub 作为 seata-go 协作的主要场所。所以 seata-go 的最新更新总是在这里。尽管通过 PR 贡献是一种明确的帮助方式,但我们仍然呼吁其他方式。 | |||
* 如果可以的话,回复别人的问题; | |||
* 帮助解决其他用户的问题; | |||
* 帮助审查他人的 PR 设计; | |||
* 帮助审查其他人在 PR 中的代码; | |||
* 讨论 seata-go以使事情更清楚; | |||
* 在Github之外宣传 seata-go 技术; | |||
* 写关于 seata-go 的博客等等。 | |||
## 代码风格 | |||
Seata-go 代码风格参考[uber-go/guide](https://github.com/uber-go/guide) 。 | |||
### IDE插件安装(非必须) | |||
*没有必要安装,如果你想在编码的时候发现问题。* | |||
安装 go fmt 和 goimports 插件,详情参考:https://github.com/golang/tools |
@@ -1,10 +0,0 @@ | |||
Apache Seata (incubating) is an effort undergoing incubation at the Apache | |||
Software Foundation (ASF), sponsored by the Apache Incubator PMC. | |||
Incubation is required of all newly accepted projects until a further review | |||
indicates that the infrastructure, communications, and decision making process | |||
have stabilized in a manner consistent with other successful ASF projects. | |||
While incubation status is not necessarily a reflection of the completeness | |||
or stability of the code, it does indicate that the project has yet to be | |||
fully endorsed by the ASF. |
@@ -0,0 +1,45 @@ | |||
GOFILES_NOVENDOR = $(shell find . -type f -name '*.go' -not -path "./vendor/*") | |||
GO_VERSION = 1.15 | |||
REGISTRY ?= seataio | |||
TAG = $(shell git rev-parse --abbrev-ref HEAD) | |||
COMMIT = git-$(shell git rev-parse --short HEAD) | |||
DATE = $(shell date +"%Y-%m-%d_%H:%M:%S") | |||
GOLDFLAGS = "-w -s -extldflags '-z now' -X github.com/opentrx/seata-golang/versions.COMMIT=$(COMMIT) -X github.com/opentrx/seata-golang/versions.BUILDDATE=$(DATE)" | |||
.PHONY: build-go | |||
build-go: | |||
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -buildmode=pie -o $(CURDIR)/dist/tc -ldflags $(GOLDFLAGS) -v ./cmd/tc | |||
.PHONY: build-bin | |||
build-bin: | |||
docker run --rm -e GOOS=linux -e GOCACHE=/tmp -e GOARCH=$(ARCH) -e GOPROXY=https://goproxy.cn \ | |||
-u $(shell id -u):$(shell id -g) \ | |||
-v $(CURDIR):/go/src/github.com/opentrx/seata-golang:ro \ | |||
-v $(CURDIR)/dist:/go/src/github.com/opentrx/seata-golang/dist/ \ | |||
golang:$(GO_VERSION) /bin/bash -c '\ | |||
cd /go/src/github.com/opentrx/seata-golang && \ | |||
make build-go ' | |||
.PHONY: build-images | |||
build-images: build-bin | |||
docker build -t $(REGISTRY)/seata-golang:$(TAG) --build-arg ARCH=amd64 -f dist/Dockerfile dist/ | |||
.PHONY: push | |||
push: | |||
docker push $(REGISTRY)/seata-golang:$(TAG) | |||
.PHONY: lint | |||
lint: | |||
@gofmt -d $(GOFILES_NOVENDOR) | |||
@if [ $$(gofmt -l $(GOFILES_NOVENDOR) | wc -l) -ne 0 ]; then \ | |||
echo "Code differs from gofmt's style" 1>&2 && exit 1; \ | |||
fi | |||
@GOOS=linux go vet ./... | |||
@GOOS=linux gosec -exclude=G204,G601 ./... | |||
.PHONY: clean | |||
clean: | |||
$(RM) dist/tc |
@@ -1,5 +0,0 @@ | |||
Apache Seata (Incubating) | |||
Copyright 2023-2025 The Apache Software Foundation | |||
This product includes software developed at | |||
The Apache Software Foundation (http://www.apache.org/). |
@@ -1,160 +1,74 @@ | |||
<!-- | |||
Licensed to the Apache Software Foundation (ASF) under one or more | |||
contributor license agreements. See the NOTICE file distributed with | |||
this work for additional information regarding copyright ownership. | |||
The ASF licenses this file to You under the Apache License, Version 2.0 | |||
(the "License"); you may not use this file except in compliance with | |||
the License. You may obtain a copy of the License at | |||
http://www.apache.org/licenses/LICENSE-2.0 | |||
Unless required by applicable law or agreed to in writing, software | |||
distributed under the License is distributed on an "AS IS" BASIS, | |||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
See the License for the specific language governing permissions and | |||
limitations under the License. | |||
--> | |||
<div style="align: center"> | |||
<img src="https://img.alicdn.com/imgextra/i1/O1CN011z0JfQ2723QgDiWuH_!!6000000007738-2-tps-1497-401.png" height="100" width="426"/> | |||
</div> | |||
# Seata-go: Simple Extensible Autonomous Transaction Architecture(Go version) | |||
[](https://github.com/apache/incubator-seata-go/actions/workflows/build.yml) [](https://www.apache.org/licenses/LICENSE-2.0.html) [](https://codecov.io/gh/apache/incubator-seata-go) [简体中文 ZH](./README_ZH.md) | |||
## What is Seata-go? | |||
Apache Seata(incubating) is a very mature distributed transaction framework, and is the de facto standard platform for distributed transaction technology in the Java field. Seata-go is the implementation version of go language in Seata multilingual ecosystem, which realizes the interoperability between Java and Go, so that Go developers can also use seata-go to realize distributed transactions. Please visit the [official website of Seata](https://seata.apache.org/) to view the quick start and documentation. | |||
The principle of seata-go is consistent with that of Seata-java, which is composed of TM, RM and TC. The functions of TC are reused in Java, and the functions of TM and RM have been connected with Seata-java. | |||
### Distributed Transaction Problem in Microservices | |||
Let's imagine a traditional monolithic application. Its business is built up with 3 modules. They use a single local data source. | |||
Naturally, data consistency will be guaranteed by the local transaction. | |||
 | |||
Things have changed in a microservices architecture. The 3 modules mentioned above are designed to be 3 services on top of 3 different data sources ([Pattern: Database per service](http://microservices.io/patterns/data/database-per-service.html)). Data consistency within every single service is naturally guaranteed by the local transaction. | |||
**But how about the whole business logic scope?** | |||
 | |||
### How Seata-go do? | |||
Seata-go is just a solution to the problem mentioned above. | |||
 | |||
Firstly, how to define a **Distributed Transaction**? | |||
We say, a **Distributed Transaction** is a **Global Transaction** which is made up with a batch of **Branch Transaction**, and normally **Branch Transaction** is just **Local Transaction**. | |||
 | |||
There are three roles in Seata-go: | |||
- **Transaction Coordinator(TC):** Maintain status of global and branch transactions, drive the global commit or rollback. | |||
- **Transaction Manager(TM):** Define the scope of global transaction: begin a global transaction, commit or rollback a global transaction. | |||
- **Resource Manager(RM):** Manage resources that branch transactions working on, talk to TC for registering branch transactions and reporting status of branch transactions, and drive the branch transaction commit or rollback. | |||
 | |||
A typical lifecycle of Seata-go managed distributed transaction: | |||
1. TM asks TC to begin a new global transaction. TC generates an XID representing the global transaction. | |||
2. XID is propagated through microservices' invoke chain. | |||
3. RM registers local transaction as a branch of the corresponding global transaction of XID to TC. | |||
4. TM asks TC for committing or rollbacking the corresponding global transaction of XID. | |||
5. TC drives all branch transactions under the corresponding global transaction of XID to finish branch committing or rollbacking. | |||
 | |||
For more details about principle and design, please go to [Seata wiki page](https://github.com/apache/incubator-seata/wiki). | |||
### History | |||
##### Alibaba | |||
- **TXC**: Taobao Transaction Constructor. Alibaba middleware team started this project since 2014 to meet the distributed transaction problems caused by application architecture change from monolithic to microservices. | |||
- **GTS**: Global Transaction Service. TXC as an Aliyun middleware product with new name GTS was published since 2016. | |||
- **Fescar**: we started the open source project Fescar based on TXC/GTS since 2019 to work closely with the community in the future. | |||
##### Ant Financial | |||
- **XTS**: Extended Transaction Service. Ant Financial middleware team developed the distributed transaction middleware since 2007, which is widely used in Ant Financial and solves the problems of data consistency across databases and services. | |||
- **DTX**: Distributed Transaction Extended. Since 2013, XTS has been published on the Ant Financial Cloud, with the name of DTX . | |||
##### Seata Community | |||
- **Seata** :Simple Extensible Autonomous Transaction Architecture. Ant Financial joins Fescar, which make it to be a more neutral and open community for distributed transaction, and Fescar be renamed to Seata. | |||
## How to run? | |||
```go | |||
go get seata.apache.org/seata-go@v2.0.0 | |||
# seata-golang | |||
[](https://github.com/opentrx/seata-golang/blob/v2/LICENSE) | |||
## Introduction | [中文](https://github.com/opentrx/seata-golang/blob/v2/docs/README_ZH.md) | |||
seata-golang is a distributed transaction middleware based on Golang. | |||
### difference between seata-glang and [seata](https://github.com/seata/seata) | |||
| feature | seata | seata-golang | remark | | |||
| ---- | :----: | :----: | --- | | |||
| AT mode | √ | √ | | | |||
| TCC mode | √ | √ | | | |||
| SAGA mode | √ | × | | | |||
| rpc | √ | √ | [dev branch](https://github.com/opentrx/seata-golang/tree/dev) | | |||
| grpc | × | √ | [v2 branch](https://github.com/opentrx/seata-golang/tree/v2) | | |||
## Architecture | |||
<img alt="seata-flow" width="500px" src="https://github.com/opentrx/seata-golang/blob/v2/docs/images/seata-flow.png" /> | |||
A typical lifecycle of Seata managed distributed transaction: | |||
- TM asks TC to begin a new global transaction. TC generates an XID representing the global transaction. | |||
- XID is propagated through microservices' invoke chain. | |||
- RM registers local transaction as a branch of the corresponding global transaction of XID to TC. | |||
- TM asks TC for committing or rolling back the corresponding global transaction of XID. | |||
- TC drives all branch transactions under the corresponding global transaction of XID to finish branch committing or rolling back. | |||
## Directory structure | |||
- cmd: to startup TC server | |||
- profiles/dev/config.yml: TC config file | |||
- tc/main.go: TC startup entrance | |||
- dist: to build in docker container | |||
- docs: documentations | |||
- pkg: TC + RM + TM implementation | |||
- server/db/*.sql: sql scripts to create DB and tables for TC | |||
## Getting started | |||
- ### TC server | |||
```bash | |||
cd ${projectpath}/cmd/tc | |||
go build -o tc_server | |||
# create database `seata` for TC server | |||
# update storage.dsn.mysql in ${projectpath}/cmd/profiles/dev/config.yml | |||
./tc_server start -config ${projectpath}/cmd/profiles/dev/config.yml | |||
``` | |||
if you want to know how to use and integrate seata-go, please refer to [apache/seata-go-samples](https://github.com/apache/incubator-seata-go-samples) | |||
## How to find the latest version | |||
Visit Seata-Go's GitHub Releases page | |||
Open: | |||
https://github.com/seata/seata-go/releases | |||
The latest tag / release is the latest stable version. | |||
## Documentation | |||
- ### Client | |||
Please refer to demo [seata-go-samples](https://github.com/opentrx/seata-go-samples) | |||
- ### Prerequisites | |||
- MySQL server | |||
- Golang version >= 1.15 | |||
- Business tables that require primary key | |||
You can view the full documentation from Seata Official Website: [Seata Website page](https://seata.apache.org/zh-cn/docs/overview/what-is-seata). | |||
## Reporting bugs | |||
Please follow the [template](.github/ISSUE_TEMPLATE/BUG_REPORT_TEMPLATE.md) for reporting any issues. | |||
## Security | |||
Please do not use our public issue tracker but refer to our [security policy](https://github.com/apache/incubator-seata/blob/2.x/SECURITY.md) | |||
## Contributing | |||
Seata-go is currently in the construction stage. Welcome colleagues in the industry to join the group and work with us to promote the construction of seata-go! If you want to contribute code to seata-go, you can refer to the [**code contribution Specification**](./CONTRIBUTING_CN.md) document to understand the specifications of the community, or you can join our community DingTalk group: 33069364 and communicate together! | |||
## Design and implementation | |||
The seata-golang AT and TCC design are actually the same as [seata](https://github.com/seata/seata). | |||
Please refer to [what-is-seata](https://seata.io/en-us/docs/overview/what-is-seata.html) for more details. | |||
## Reference | |||
- [what is seata AT mode?](https://seata.io/en-us/docs/dev/mode/at-mode.html) | |||
- [what is seata TCC mode?](https://seata.io/en-us/docs/dev/mode/tcc-mode.html) | |||
- [GRPC](https://grpc.io/) | |||
- [dubbogo](https://github.com/dubbogo) | |||
- [mysql-driver](https://github.com/opentrx/mysql) | |||
- [seata-go-samples](https://github.com/opentrx/seata-go-samples) | |||
## Contact | |||
Please contact us via DingTalk app if you have any issues. The chat group ID is 33069364. | |||
<img alt="DingTalk Group" src="https://github.com/opentrx/seata-golang/blob/dev/docs/pics/33069364.png" width="200px" /> | |||
* Mailing list: | |||
* dev@seata.apache.org , for dev/user discussion. [subscribe](mailto:dev-subscribe@seata.apache.org), [unsubscribe](mailto:dev-unsubscribe@seata.apache.org), [archive](https://lists.apache.org/list.html?dev@seata.apache.org) | |||
* Online chat: | |||
| Dingtalk group | Wechat official account | QQ group | Wechat assistant | | |||
|:---------------------------------------------------------------------------------------------------------------------------:|:----------------------------------------------------------------------------------------------------------------------------:|:---------------------------------------------------------------------------------------------------------------------:|:-------------------------------------------------------------------------------------------------------------------:| | |||
| <img src="https://seata.apache.org/zh-cn/assets/images/dingtalk-group-67f42c9466fb2268b6927bb16b549d6c.jpg" width="150" /> | <img src="https://seata.apache.org/zh-cn/assets/images/wechat-official-467d10305f5449e6b2096e65d23a9d02.jpg" width="150" /> | <img src="https://seata.apache.org/zh-cn/assets/images/qq-group-8d8a89699cdb9ba8818364069475ba96.jpg" width="150" /> | <img src="https://seata.apache.org/zh-cn/assets/images/wechat-f8a87a96973942b826e32d1aed9bc8d9.jpg" width="150" /> | | |||
## Seata ecosystem | |||
* [Seata Website](https://github.com/apache/incubator-seata.github.io) - Seata official website | |||
* [Seata](https://github.com/apache/incubator-seata)- Seata client and server | |||
* [Seata GoLang](https://github.com/apache/incubator-seata-go) - Seata GoLang client and server | |||
* [Seata Samples](https://github.com/apache/incubator-seata-samples) - Samples for Seata | |||
* [Seata GoLang Samples](https://github.com/apache/incubator-seata-go-samples) - Samples for Seata GoLang | |||
* [Seata K8s](https://github.com/apache/incubator-seata-k8s) - Seata integration with k8s | |||
* [Seata CLI](https://github.com/apache/incubator-seata-ctl) - CLI tool for Seata | |||
## Contributors | |||
This project exists thanks to all the people who contribute. [[Contributors](https://github.com/apache/incubator-seata-go/graphs/contributors)]. | |||
## Contributing | |||
Welcome to raise up issue or pull-request to seata-golang! | |||
To contribute, fork from opentrx/seata-golang and push branch to your repo, then open a pull-request. | |||
## License | |||
Seata-go is under the Apache 2.0 license. See the [LICENSE](https://github.com/apache/incubator-seata-go/blob/master/LICENSE) file for details. | |||
seata-golang software is licenced under the Apache License Version 2.0. See the [LICENSE](https://github.com/opentrx/seata-golang/blob/v2/LICENSE) file for details. |
@@ -1,164 +0,0 @@ | |||
<!-- | |||
Licensed to the Apache Software Foundation (ASF) under one or more | |||
contributor license agreements. See the NOTICE file distributed with | |||
this work for additional information regarding copyright ownership. | |||
The ASF licenses this file to You under the Apache License, Version 2.0 | |||
(the "License"); you may not use this file except in compliance with | |||
the License. You may obtain a copy of the License at | |||
http://www.apache.org/licenses/LICENSE-2.0 | |||
Unless required by applicable law or agreed to in writing, software | |||
distributed under the License is distributed on an "AS IS" BASIS, | |||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
See the License for the specific language governing permissions and | |||
limitations under the License. | |||
--> | |||
<div style="align: center"> | |||
<img src="https://img.alicdn.com/imgextra/i1/O1CN011z0JfQ2723QgDiWuH_!!6000000007738-2-tps-1497-401.png" height="100" width="426"/> | |||
</div> | |||
# Seata-go:简单可扩展的自主事务架构(Go 语言版本) | |||
[](https://github.com/apache/incubator-seata-go/actions/workflows/build.yml) [](https://www.apache.org/licenses/LICENSE-2.0.html) [](https://codecov.io/gh/apache/incubator-seata-go) [English](./README.md) | |||
## 什么是 Seata-go? | |||
Apache Seata(incubating)是一个非常成熟的分布式事务框架,是 Java 领域事实上的标准分布式事务平台。Seata-go 是其在多语言生态中 Go 语言的实现版本,实现了 Java 与 Go 之间的互操作,使得 Go 开发者也可以使用 seata-go 实现分布式事务。请访问 [Seata 官网](https://seata.apache.org/) 获取快速入门和文档。 | |||
Seata-go 的原理与 Seata-java 一致,由 TM、RM 和 TC 三部分组成。其中 TC 功能复用 Java 的实现,而 TM 和 RM 则已与 Seata-java 对接。 | |||
### 微服务中的分布式事务问题 | |||
假设我们有一个传统的单体应用,其业务由三个模块组成,使用一个本地数据源,自然由本地事务保障数据一致性。 | |||
 | |||
但在微服务架构中,这三个模块被设计成了三个不同的服务,分别使用不同的数据源([数据库每服务模式](http://microservices.io/patterns/data/database-per-service.html))。单个服务内的数据一致性可以通过本地事务保障。 | |||
但**整个业务范围的一致性如何保障?** | |||
 | |||
### Seata-go 如何做? | |||
Seata-go 就是为了解决上述问题而生。 | |||
 | |||
首先,如何定义一个**分布式事务**? | |||
我们认为,分布式事务是一个**全局事务**,由一组**分支事务**组成,而**分支事务**通常就是**本地事务**。 | |||
 | |||
Seata-go 中有三个角色: | |||
- **事务协调器(TC)**:维护全局和分支事务的状态,驱动全局提交或回滚。 | |||
- **事务管理器(TM)**:定义全局事务的范围,开始、提交或回滚全局事务。 | |||
- **资源管理器(RM)**:管理分支事务所处理的资源,与 TC 通信注册分支事务并报告状态,驱动分支事务提交或回滚。 | |||
 | |||
Seata-go 分布式事务的典型生命周期如下: | |||
1. TM 请求 TC 开启一个新的全局事务,TC 生成表示全局事务的 XID。 | |||
2. XID 在微服务调用链中传播。 | |||
3. RM 将本地事务注册为该 XID 对应的全局事务的分支事务。 | |||
4. TM 请求 TC 提交或回滚该 XID 对应的全局事务。 | |||
5. TC 驱动该 XID 对应的所有分支事务进行提交或回滚。 | |||
 | |||
更多原理和设计细节,请参阅 [Seata Wiki 页面](https://github.com/apache/incubator-seata/wiki)。 | |||
### 历史背景 | |||
##### 阿里巴巴 | |||
- **TXC**:淘宝事务构建器。2014 年阿里中间件团队启动,用于应对从单体架构转向微服务带来的分布式事务问题。 | |||
- **GTS**:全局事务服务。2016 年 TXC 在阿里云上线,更名为 GTS。 | |||
- **Fescar**:2019 年开始基于 TXC/GTS 启动开源项目 Fescar,与社区合作。 | |||
##### 蚂蚁金服 | |||
- **XTS**:扩展事务服务。自 2007 年开始开发的分布式事务中间件,被广泛应用于蚂蚁金服,解决跨库跨服务数据一致性问题。 | |||
- **DTX**:分布式事务扩展。2013 年起在蚂蚁金服云发布,命名为 DTX。 | |||
##### Seata 社区 | |||
- **Seata**:简单可扩展的自主事务架构。蚂蚁金服加入 Fescar,使其成为一个更加中立开放的社区,Fescar 更名为 Seata。 | |||
## 如何运行? | |||
```go | |||
go get seata.apache.org/seata-go@2.0.0 | |||
``` | |||
如果你想了解如何使用和集成 seata-go,请参考 [apache/seata-go-samples](https://github.com/apache/incubator-seata-go-samples) | |||
## 如何查找最新版本 | |||
访问 Seata-Go 的 GitHub Releases 页面 | |||
打开:https://github.com/seata/seata-go/releases | |||
最新的 tag / release 就是目前的最新稳定版本。 | |||
## 文档 | |||
你可以访问 Seata 官方网站获取完整文档:[Seata 官网](https://seata.apache.org/zh-cn/docs/overview/what-is-seata) | |||
## 问题报告 | |||
若有问题,请遵循 [模板](./.github/ISSUE_TEMPLATE/BUG_REPORT_TEMPLATE.md) 报告问题。 | |||
## 安全 | |||
请勿使用公开的问题跟踪器,详情请参阅我们的 [安全政策](https://github.com/apache/incubator-seata/blob/2.x/SECURITY.md) | |||
## 参与贡献 | |||
Seata-go 当前处于建设阶段,欢迎业界同仁加入我们,共同推进 Seata-go 建设!如果你想为 Seata-go 贡献代码,请参考 [代码贡献规范](./CONTRIBUTING_CN.md),也可以加入我们的社区钉钉群:33069364 一起交流! | |||
## 联系方式 | |||
* 邮件列表: | |||
* dev@seata.apache.org - 用于开发/用户讨论 [订阅](mailto:dev-subscribe@seata.apache.org)、[取消订阅](mailto:dev-unsubscribe@seata.apache.org)、[归档](https://lists.apache.org/list.html?dev@seata.apache.org) | |||
* 在线交流: | |||
| 钉钉 | 微信公众号 | QQ | 微信助手 | | |||
|:---------------------------------------------------------------------------------------------------------------------------:|:----------------------------------------------------------------------------------------------------------------------------:|:---------------------------------------------------------------------------------------------------------------------:|:-------------------------------------------------------------------------------------------------------------------:| | |||
| <img src="https://seata.apache.org/zh-cn/assets/images/dingtalk-group-67f42c9466fb2268b6927bb16b549d6c.jpg" width="150" /> | <img src="https://seata.apache.org/zh-cn/assets/images/wechat-official-467d10305f5449e6b2096e65d23a9d02.jpg" width="150" /> | <img src="https://seata.apache.org/zh-cn/assets/images/qq-group-8d8a89699cdb9ba8818364069475ba96.jpg" width="150" /> | <img src="https://seata.apache.org/zh-cn/assets/images/wechat-f8a87a96973942b826e32d1aed9bc8d9.jpg" width="150" /> | | |||
## Seata 生态系统 | |||
* [Seata 官网](https://github.com/apache/incubator-seata.github.io)- Seata官方网站 | |||
* [Seata](https://github.com/apache/incubator-seata) - Seata 客户端和服务端 | |||
* [Seata GoLang](https://github.com/apache/incubator-seata-go) - Seata Go 客户端和服务端 | |||
* [Seata 示例](https://github.com/apache/incubator-seata-samples)- Seata 示例 | |||
* [Seata Go 示例](https://github.com/apache/incubator-seata-go-samples)- Seata GoLang 示例 | |||
* [Seata K8s 集成](https://github.com/apache/incubator-seata-k8s)- Seata 与 K8S 集成 | |||
* [Seata 命令行工具](https://github.com/apache/incubator-seata-ctl)- Seata CLI 工具 | |||
## 贡献者 | |||
Seata-go感谢所有贡献者的付出。[[贡献者列表](https://github.com/apache/incubator-seata-go/graphs/contributors)] | |||
## 许可证 | |||
Seata-go 使用 Apache 2.0 协议,详情请查看 [LICENSE 文件](https://github.com/apache/incubator-seata-go/blob/master/LICENSE) |
@@ -1,78 +0,0 @@ | |||
<!-- | |||
Licensed to the Apache Software Foundation (ASF) under one or more | |||
contributor license agreements. See the NOTICE file distributed with | |||
this work for additional information regarding copyright ownership. | |||
The ASF licenses this file to You under the Apache License, Version 2.0 | |||
(the "License"); you may not use this file except in compliance with | |||
the License. You may obtain a copy of the License at | |||
http://www.apache.org/licenses/LICENSE-2.0 | |||
Unless required by applicable law or agreed to in writing, software | |||
distributed under the License is distributed on an "AS IS" BASIS, | |||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
See the License for the specific language governing permissions and | |||
limitations under the License. | |||
--> | |||
### 0.1.0-rc1 | |||
<details> | |||
<summary><mark>Release notes</mark></summary> | |||
### Seata-go 0.1.0-rc1 | |||
Seata-go 0.1.0-rc1 Released. | |||
Seata-go is an easy-to-use, high-performance, open source distributed transaction solution. | |||
The version is updated as follows: | |||
### feature: | |||
- [[#1](https://github.com/apache/incubator-seata-go/commit/06b9969bb3fd24071adc271dc543c3eb684070c9)] initialize project structure and support tcc local | |||
- [[#2](https://github.com/apache/incubator-seata-go/commit/80913fa73e38fd3c159dcd28804344b9a87f718c)] add github Actions | |||
- [[#122](https://github.com/apache/incubator-seata-go/pull/122)] feat: add two phase and tcc dubbo | |||
- [[#127](https://github.com/apache/incubator-seata-go/pull/127)] feat: transaction at datasource | |||
### bugfix: | |||
- [[#5](https://github.com/apache/incubator-seata-go/commit/48f1b6bf6c8890d649ceac3d048f61695dce2f7a)] fix cli bug | |||
- [[#15](https://github.com/apache/incubator-seata-go/commit/de615531e9d17af66067c54452ee5bce2d670008)] fix branch commit bug | |||
- [[#34](https://github.com/apache/incubator-seata-go/commit/846a3b336194f9d188f07bf6af65f617b0baf489)] style:change bool to struct{} | |||
- [[#130](https://github.com/apache/incubator-seata-go/pull/130)] fix: getty session auto close bug | |||
- [[#155](https://github.com/apache/incubator-seata-go/pull/155)] bugfix: fix rollback response status bug | |||
### optimize: | |||
- [[#3](https://github.com/apache/incubator-seata-go/commit/65c2e1ed676a2306eb10f7d43e3bf5b37271ee3e)] adjust the structure of the project | |||
- [[#18](https://github.com/apache/incubator-seata-go/commit/de615531e9d17af66067c54452ee5bce2d670008)] remove goetty | |||
- [[#19](https://github.com/apache/incubator-seata-go/commit/de615531e9d17af66067c54452ee5bce2d670008)] optimize codec code | |||
- [[#125](https://github.com/apache/incubator-seata-go/pull/125)] optimize named for the resource manager api | |||
- [[#165](https://github.com/apache/incubator-seata-go/pull/165)] test: add unit test and labeler workflow | |||
### test: | |||
- [[#9f4d8](https://github.com/apache/incubator-seata-go/commit/9f4d8cc0b6f1e26860cded5ab05b504ad6a6d6ff)] add unit test for codec | |||
### doc: | |||
- [[#0](https://github.com/apache/incubator-seata-go/commit/fcda132629032321a7cc733a7a2ed02e05c2151b)] hello world | |||
- [[#146](https://github.com/apache/incubator-seata-go/pull/146)] doc: add license | |||
- [[#153](https://github.com/apache/incubator-seata-go/pull/153)] docs: add readme ,contributing and pr template doc | |||
- [[#167](https://github.com/apache/incubator-seata-go/pull/167)] fix typo in reademe | |||
### contributors: | |||
Thanks to these contributors for their code commits. Please report an unintended omission. | |||
- [AlexStocks](https://github.com/AlexStocks) | |||
- [luky116](https://github.com/luky116) | |||
- [106umao](https://github.com/106umao) | |||
- [liiibpm](https://github.com/liiibpm) | |||
- [cgDeepLearn](https://github.com/cgDeepLearn) | |||
- [Penglq](https://github.com/Penglq) | |||
Also, we receive many valuable issues, questions and advices from our community. Thanks for you all. | |||
</detail> |
@@ -1,78 +0,0 @@ | |||
<!-- | |||
Licensed to the Apache Software Foundation (ASF) under one or more | |||
contributor license agreements. See the NOTICE file distributed with | |||
this work for additional information regarding copyright ownership. | |||
The ASF licenses this file to You under the Apache License, Version 2.0 | |||
(the "License"); you may not use this file except in compliance with | |||
the License. You may obtain a copy of the License at | |||
http://www.apache.org/licenses/LICENSE-2.0 | |||
Unless required by applicable law or agreed to in writing, software | |||
distributed under the License is distributed on an "AS IS" BASIS, | |||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
See the License for the specific language governing permissions and | |||
limitations under the License. | |||
--> | |||
### 0.1.0-rc1 | |||
<details> | |||
<summary><mark>Release notes</mark></summary> | |||
### Seata-go 0.1.0-rc1 | |||
Seata-go 0.1.0-rc1 发布。 | |||
Seata-go 是一款开源的分布式事务解决方案,提供高性能和简单易用的分布式事务服务。 | |||
此版本更新如下: | |||
### feature: | |||
- [[#1](https://github.com/apache/incubator-seata-go/commit/06b9969bb3fd24071adc271dc543c3eb684070c9)] 项目初始化,并且支持TCC本地模式 | |||
- [[#2](https://github.com/apache/incubator-seata-go/commit/80913fa73e38fd3c159dcd28804344b9a87f718c)] 添加 github 工作流 | |||
- [[#122](https://github.com/apache/incubator-seata-go/pull/122)] 添加二阶段提交和TCC dubbo调用 | |||
- [[#127](https://github.com/apache/incubator-seata-go/pull/127)] 添加事务数据源代理 | |||
### bugfix: | |||
- [[#5](https://github.com/apache/incubator-seata-go/commit/48f1b6bf6c8890d649ceac3d048f61695dce2f7a)] 修复cli的问题 | |||
- [[#15](https://github.com/apache/incubator-seata-go/commit/de615531e9d17af66067c54452ee5bce2d670008)] 修复提交分支事务的问题 | |||
- [[#34](https://github.com/apache/incubator-seata-go/commit/846a3b336194f9d188f07bf6af65f617b0baf489)] 将bool改为struct{} | |||
- [[#130](https://github.com/apache/incubator-seata-go/pull/130)] 修复getty 自动关闭session的问题 | |||
- [[#155](https://github.com/apache/incubator-seata-go/pull/155)] 修复分支事务回滚时返回值status的问题 | |||
### optimize: | |||
- [[#3](https://github.com/apache/incubator-seata-go/commit/65c2e1ed676a2306eb10f7d43e3bf5b37271ee3e)] 调整项目结构 | |||
- [[#18](https://github.com/apache/incubator-seata-go/commit/de615531e9d17af66067c54452ee5bce2d670008)] 移除 goetty 包依赖 | |||
- [[#19](https://github.com/apache/incubator-seata-go/commit/de615531e9d17af66067c54452ee5bce2d670008)] 重构 codec 的代码 | |||
- [[#125](https://github.com/apache/incubator-seata-go/pull/125)] 重名 rm api 的接口 | |||
- [[#165](https://github.com/apache/incubator-seata-go/pull/165)] 完善 github 工作流 | |||
### test: | |||
- [[#9f4d8](https://github.com/apache/incubator-seata-go/commit/9f4d8cc0b6f1e26860cded5ab05b504ad6a6d6ff)] 添加codec的单测 | |||
### doc: | |||
- [[#0](https://github.com/apache/incubator-seata-go/commit/fcda132629032321a7cc733a7a2ed02e05c2151b)] hello world | |||
- [[#146](https://github.com/apache/incubator-seata-go/pull/146)] 添加 license 文件 | |||
- [[#153](https://github.com/apache/incubator-seata-go/pull/153)] 添加 readme 、contributing 和 pr template 文件 | |||
- [[#167](https://github.com/apache/incubator-seata-go/pull/167)] 完善 reamdme 文件格式 | |||
### contributors: | |||
非常感谢以下 contributors 的代码贡献。若有无意遗漏,请报告。 | |||
- [AlexStocks](https://github.com/AlexStocks) | |||
- [luky116](https://github.com/luky116) | |||
- [106umao](https://github.com/106umao) | |||
- [liiibpm](https://github.com/liiibpm) | |||
- [cgDeepLearn](https://github.com/cgDeepLearn) | |||
- [Penglq](https://github.com/Penglq) | |||
同时,我们收到了社区反馈的很多有价值的issue和建议,非常感谢大家。 | |||
</detail> |
@@ -1,156 +0,0 @@ | |||
<!-- | |||
Licensed to the Apache Software Foundation (ASF) under one or more | |||
contributor license agreements. See the NOTICE file distributed with | |||
this work for additional information regarding copyright ownership. | |||
The ASF licenses this file to You under the Apache License, Version 2.0 | |||
(the "License"); you may not use this file except in compliance with | |||
the License. You may obtain a copy of the License at | |||
http://www.apache.org/licenses/LICENSE-2.0 | |||
Unless required by applicable law or agreed to in writing, software | |||
distributed under the License is distributed on an "AS IS" BASIS, | |||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
See the License for the specific language governing permissions and | |||
limitations under the License. | |||
--> | |||
### 1.0.2-RC1 | |||
<details> | |||
<summary><mark>Release notes</mark></summary> | |||
### Seata-go 1.0.2-RC1 | |||
Seata-go 1.0.2-RC1 Released. | |||
Seata-go is an easy-to-use, high-performance, open source distributed transaction solution. | |||
The version is updated as follows: | |||
### feature: | |||
- [[#190](https://github.com/apache/incubator-seata-go/pull/190)] add TCC branch report | |||
- [[#158](https://github.com/apache/incubator-seata-go/pull/158)] TCC mode supports grpc call | |||
- [[#213](https://github.com/apache/incubator-seata-go/pull/213)] support data source proxy function | |||
- [[#240](https://github.com/apache/incubator-seata-go/pull/240)] add undo log manager delete | |||
- [[#243](https://github.com/apache/incubator-seata-go/pull/243)] add update sql parser | |||
- [[#191](https://github.com/apache/incubator-seata-go/pull/191)] add fence for TCC, and add fence sample in TCC local mode | |||
- [[#264](https://github.com/apache/incubator-seata-go/pull/264)] add update sql parser and remove tidb parser | |||
- [[#280](https://github.com/apache/incubator-seata-go/pull/280)] TCC supports http calling | |||
- [[#245](https://github.com/apache/incubator-seata-go/pull/245)] support hasLogTable logic | |||
- [[#288](https://github.com/apache/incubator-seata-go/pull/288)] add MySQL update SQL undo log builder | |||
- [[#296](https://github.com/apache/incubator-seata-go/pull/296)] add MySQL delete SQL undo log builder | |||
- [[#303](https://github.com/apache/incubator-seata-go/pull/303)] add sync worker | |||
- [[#289](https://github.com/apache/incubator-seata-go/pull/289)] add MySQL update SQL after undo log builder | |||
- [[#294](https://github.com/apache/incubator-seata-go/pull/294)] add MySQL table meta query | |||
- [[#309](https://github.com/apache/incubator-seata-go/pull/309)] init compressor type | |||
- [[#301](https://github.com/apache/incubator-seata-go/pull/301)] add MySQL multi SQL undo log builder | |||
- [[#321](https://github.com/apache/incubator-seata-go/pull/321)] add deflate compress | |||
- [[#324](https://github.com/apache/incubator-seata-go/pull/324)] add LZ4 compressor | |||
- [[#327](https://github.com/apache/incubator-seata-go/pull/327)] add zstd compressor | |||
- [[#322](https://github.com/apache/incubator-seata-go/pull/322)] add gzip compressor | |||
- [[#307](https://github.com/apache/incubator-seata-go/pull/307)] add flush undo log | |||
- [[#329](https://github.com/apache/incubator-seata-go/pull/329)] add zip compressor | |||
- [[#325](https://github.com/apache/incubator-seata-go/pull/325)] add MySQL multi update SQL undo log builder | |||
- [[#330](https://github.com/apache/incubator-seata-go/pull/330)] add MySQL multi delete SQL undo log builder | |||
- [[#319](https://github.com/apache/incubator-seata-go/pull/319)] add select for update | |||
- [[#320](https://github.com/apache/incubator-seata-go/pull/320)] add undo logic | |||
- [[#337](https://github.com/apache/incubator-seata-go/pull/337)] add insert undo log | |||
- [[#355](https://github.com/apache/incubator-seata-go/pull/355)] support judging the number of undo log storage fields according to the configuration | |||
- [[#365](https://github.com/apache/incubator-seata-go/pull/365)] do dirty data check before rolling back AT | |||
### bugfix: | |||
- [[#176](https://github.com/apache/incubator-seata-go/pull/176)] fix unit test bug of message | |||
- [[#237](https://github.com/apache/incubator-seata-go/pull/237)] fix the bug of registering resources when executing the OpenConnector function | |||
- [[#230](https://github.com/apache/incubator-seata-go/pull/230)] fix the bug of remote asynchronous call infinite loop | |||
- [[#258](https://github.com/apache/incubator-seata-go/pull/258)] fix global transation time out bug | |||
- [[#263](https://github.com/apache/incubator-seata-go/pull/263)] fix mock bug | |||
- [[#326](https://github.com/apache/incubator-seata-go/pull/326)] fix fanout test data race | |||
- [[#350](https://github.com/apache/incubator-seata-go/pull/350)] fix panic bug | |||
- [[#359](https://github.com/apache/incubator-seata-go/pull/359)] fix insert undo log bug | |||
- [[#368](https://github.com/apache/incubator-seata-go/pull/368)] fix AT rollback sample bug | |||
- [[#363](https://github.com/apache/incubator-seata-go/pull/363)] fix meta data bug | |||
- [[#365](https://github.com/apache/incubator-seata-go/pull/365)] fix decode undo log bug | |||
### optimize: | |||
- [[#187](https://github.com/apache/incubator-seata-go/pull/187)] optimize way of init seata-go | |||
- [[#196](https://github.com/apache/incubator-seata-go/pull/196)] optimize remoting method's params | |||
- [[#200](https://github.com/apache/incubator-seata-go/pull/200)] add TCC grpc sample and optimize register resource and branch register | |||
- [[#208](https://github.com/apache/incubator-seata-go/pull/208)] optimize remove unnecessary codes | |||
- [[#202](https://github.com/apache/incubator-seata-go/pull/202)] optimize workflow, add condecov and issue, stale robot | |||
- [[#215](https://github.com/apache/incubator-seata-go/pull/215)] optimize the time parameter to improve readability | |||
- [[#179](https://github.com/apache/incubator-seata-go/pull/179)] support instance BusinessActionContext outside the TCC try method | |||
- [[#198](https://github.com/apache/incubator-seata-go/pull/198)] optimize function's parameters into one struct-rm_api.go | |||
- [[#235](https://github.com/apache/incubator-seata-go/pull/235)] adjust MessageType enumeration value naming convention | |||
- [[#238](https://github.com/apache/incubator-seata-go/pull/238)] add some todo comment, add a undo hook sample | |||
- [[#229](https://github.com/apache/incubator-seata-go/pull/229)] add unit testing for common | |||
- [[#261](https://github.com/apache/incubator-seata-go/pull/261)] optimize nested loop retries | |||
- [[#284](https://github.com/apache/incubator-seata-go/pull/284)] optimize retry logic | |||
- [[#286](https://github.com/apache/incubator-seata-go/pull/286)] separate the initialization logic of tm and rm | |||
- [[#287](https://github.com/apache/incubator-seata-go/pull/287)] fefactor seata conn logic | |||
- [[#281](https://github.com/apache/incubator-seata-go/pull/281)] optimize global transaction usage | |||
- [[#295](https://github.com/apache/incubator-seata-go/pull/295)] fefactor seata conn logic | |||
- [[#302](https://github.com/apache/incubator-seata-go/pull/302)] update dubbo-go version | |||
- [[#336](https://github.com/apache/incubator-seata-go/pull/336)] optimize at overall process | |||
- [[#346](https://github.com/apache/incubator-seata-go/pull/346)] optimize AT commit transaction process | |||
- [[#352](https://github.com/apache/incubator-seata-go/pull/352)] optimize get meta data | |||
- [[#354](https://github.com/apache/incubator-seata-go/pull/354)] optimize AT commit transaction process | |||
- [[#353](https://github.com/apache/incubator-seata-go/pull/353)] modify some receiver name | |||
- [[#356](https://github.com/apache/incubator-seata-go/pull/356)] optimize AT rollback transaction process | |||
### test: | |||
- [[#154](https://github.com/apache/incubator-seata-go/pull/154)] add unit test for message | |||
- [[#163](https://github.com/apache/incubator-seata-go/pull/163)] add unit test for tm | |||
- [[#203](https://github.com/apache/incubator-seata-go/pull/203)] add unit test for getty | |||
- [[#204](https://github.com/apache/incubator-seata-go/pull/204)] add unit test for dubbo transtation filter | |||
- [[#210](https://github.com/apache/incubator-seata-go/pull/210)] add unit test for Tcc branch report | |||
- [[#192](https://github.com/apache/incubator-seata-go/pull/192)] add unit test for rm | |||
- [[#229](https://github.com/apache/incubator-seata-go/pull/229)] add unit test for common | |||
- [[#299](https://github.com/apache/incubator-seata-go/pull/299)] add unit test for SQL Parser | |||
- [[#332](https://github.com/apache/incubator-seata-go/pull/332)] add unit test for multi delete undo log | |||
- [[#358](https://github.com/apache/incubator-seata-go/pull/358)] add AT rollback sample | |||
### doc: | |||
- [[#202](https://github.com/apache/incubator-seata-go/pull/202)] optimize workflow, add condecov and issue | |||
- [[#254](https://github.com/apache/incubator-seata-go/pull/254)] add license automatic check script | |||
- [[#305](https://github.com/apache/incubator-seata-go/pull/305)] config github action not to automatically close pr or issue | |||
### contributors: | |||
Thanks to these contributors for their code commits. Please report an unintended omission. | |||
- [AlexStocks](https://github.com/AlexStocks) | |||
- [luky116](https://github.com/luky116) | |||
- [106umao](https://github.com/106umao) | |||
- [liiibpm](https://github.com/liiibpm) | |||
- [elrond-g](https://github.com/elrond-g) | |||
- [wang1309](https://github.com/wang1309) | |||
- [iSuperCoder](https://github.com/apache/incubator-seata-go/commits?author=iSuperCoder) | |||
- [a631807682](https://github.com/apache/incubator-seata-go/commits?author=a631807682) | |||
- [betterwinsone](https://github.com/apache/incubator-seata-go/commits?author=betterwinsone) | |||
- [jasondeng1997](https://github.com/apache/incubator-seata-go/commits?author=jasondeng1997) | |||
- [chuntaojun](https://github.com/apache/incubator-seata-go/commits?author=chuntaojun) | |||
- [complone](https://github.com/apache/incubator-seata-go/commits?author=complone) | |||
- [miaoxueyu](https://github.com/apache/incubator-seata-go/commits?author=miaoxueyu) | |||
- [PangXing](https://github.com/apache/incubator-seata-go/commits?author=PangXing) | |||
- [georgehao](https://github.com/apache/incubator-seata-go/commits?author=georgehao) | |||
- [baerwang](https://github.com/apache/incubator-seata-go/commits?author=baerwang) | |||
- [raspberry-hu](https://github.com/apache/incubator-seata-go/commits?author=raspberry-hu) | |||
- [WyattJia](https://github.com/apache/incubator-seata-go/commits?author=WyattJia) | |||
- [Code-Fight](https://github.com/Code-Fight) | |||
- [betterwinsone](https://github.com/betterwinsonet) | |||
Also, we receive many valuable issues, questions and advices from our community. Thanks for you all. | |||
</detail> |
@@ -1,157 +0,0 @@ | |||
<!-- | |||
Licensed to the Apache Software Foundation (ASF) under one or more | |||
contributor license agreements. See the NOTICE file distributed with | |||
this work for additional information regarding copyright ownership. | |||
The ASF licenses this file to You under the Apache License, Version 2.0 | |||
(the "License"); you may not use this file except in compliance with | |||
the License. You may obtain a copy of the License at | |||
http://www.apache.org/licenses/LICENSE-2.0 | |||
Unless required by applicable law or agreed to in writing, software | |||
distributed under the License is distributed on an "AS IS" BASIS, | |||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
See the License for the specific language governing permissions and | |||
limitations under the License. | |||
--> | |||
### 1.0.2-RC1 | |||
<details> | |||
<summary><mark>Release notes</mark></summary> | |||
### Seata-go 1.0.2-RC1 | |||
Seata-go 1.0.2-RC1 发布。 | |||
Seata-go 是一款开源的分布式事务解决方案,提供高性能和简单易用的分布式事务服务。 | |||
此版本更新如下: | |||
### feature: | |||
- [[#190](https://github.com/apache/incubator-seata-go/pull/190)] 添加分支状态上报接口 | |||
- [[#158](https://github.com/apache/incubator-seata-go/pull/158)] TCC 模式支持 grapc 调用 | |||
- [[#213](https://github.com/apache/incubator-seata-go/pull/213)] 支持数据源代理功能 | |||
- [[#240](https://github.com/apache/incubator-seata-go/pull/240)] 删除日志管理功能 | |||
- [[#243](https://github.com/apache/incubator-seata-go/pull/243)] 添加 Update SQL 语法解析器 | |||
- [[#191](https://github.com/apache/incubator-seata-go/pull/191)] 支持 TCC 防悬挂、空回滚处理功能 | |||
- [[#264](https://github.com/apache/incubator-seata-go/pull/264)] 添加更新sql解析器并删除 tidb 解析器 | |||
- [[#280](https://github.com/apache/incubator-seata-go/pull/280)] TCC 支持 http 调用 | |||
- [[#245](https://github.com/apache/incubator-seata-go/pull/245)] 支持 hasLogTable 判断逻辑 | |||
- [[#288](https://github.com/apache/incubator-seata-go/pull/288)] 添加 update SQL 的 undo log 生成功能 | |||
- [[#296](https://github.com/apache/incubator-seata-go/pull/296)] 添加 delete SQL 的 undo log 生成功能 | |||
- [[#303](https://github.com/apache/incubator-seata-go/pull/303)] 添加异步处理器 | |||
- [[#289](https://github.com/apache/incubator-seata-go/pull/289)] 撤消日志生成器后添加 MySQL 更新 | |||
- [[#294](https://github.com/apache/incubator-seata-go/pull/294)] 添加 MySQL 元数据查询 | |||
- [[#309](https://github.com/apache/incubator-seata-go/pull/309)] 初始化压缩类型 | |||
- [[#301](https://github.com/apache/incubator-seata-go/pull/301)] 添加 Multi SQL 的 undo log 生成功能 | |||
- [[#321](https://github.com/apache/incubator-seata-go/pull/321)] 添加 deflate 压缩功能 | |||
- [[#324](https://github.com/apache/incubator-seata-go/pull/324)] 添加 lz4 压缩功能 | |||
- [[#327](https://github.com/apache/incubator-seata-go/pull/327)] 添加 zstd 压缩功能 | |||
- [[#322](https://github.com/apache/incubator-seata-go/pull/322)] 添加 gzip 压缩功能 | |||
- [[#307](https://github.com/apache/incubator-seata-go/pull/307)] 添加 flush undo log 功能 | |||
- [[#329](https://github.com/apache/incubator-seata-go/pull/329)] 添加 zip 压缩功能 | |||
- [[#325](https://github.com/apache/incubator-seata-go/pull/325)] 添加 Multi update SQL 的 undo log 生成功能 | |||
- [[#330](https://github.com/apache/incubator-seata-go/pull/330)] 添加 Multi delete SQL 的 undo log 生成功能 | |||
- [[#319](https://github.com/apache/incubator-seata-go/pull/319)] 添加选择更新执行器 | |||
- [[#320](https://github.com/apache/incubator-seata-go/pull/320)] 添加 undo 逻辑 | |||
- [[#337](https://github.com/apache/incubator-seata-go/pull/337)] 添加插入 undo log 逻辑 | |||
- [[#355](https://github.com/apache/incubator-seata-go/pull/355)] 支持根据配置判断 undo log 保存字段个数 | |||
- [[#365](https://github.com/apache/incubator-seata-go/pull/365)] 回滚 AT 之前做脏数据校验 | |||
### bugfix: | |||
- [[#176](https://github.com/apache/incubator-seata-go/pull/176)] 修复 message 的单测的 bug | |||
- [[#237](https://github.com/apache/incubator-seata-go/pull/237)] 修复在执行 OpenConnector 函数时候注册资源的 bug | |||
- [[#230](https://github.com/apache/incubator-seata-go/pull/230)] 修复远程异步调用无限循环的bug | |||
- [[#258](https://github.com/apache/incubator-seata-go/pull/258)] 修复全局事务超时的 bug | |||
- [[#263](https://github.com/apache/incubator-seata-go/pull/263)] 修复 mock 数据的 bug | |||
- [[#326](https://github.com/apache/incubator-seata-go/pull/326)] 修复 fanout 单元测试 bug | |||
- [[#350](https://github.com/apache/incubator-seata-go/pull/350)] 修复 panic 的bug | |||
- [[#359](https://github.com/apache/incubator-seata-go/pull/359)] 修复插入 undo log 的 MySQL 参数 bug | |||
- [[#360](https://github.com/apache/incubator-seata-go/pull/360)] 修复 AT 回滚例子 bug | |||
- [[#363](https://github.com/apache/incubator-seata-go/pull/363)] 修复 meta data bug | |||
- [[#365](https://github.com/apache/incubator-seata-go/pull/365)] 修复反序列化 undo log bug | |||
### optimize: | |||
- [[#187](https://github.com/apache/incubator-seata-go/pull/187)] 优化 seata-go 初始化流程 | |||
- [[#196](https://github.com/apache/incubator-seata-go/pull/196)] 优化远程调用方法参数 | |||
- [[#200](https://github.com/apache/incubator-seata-go/pull/200)] 添加 tcc grpc 样例,优化注册资源和分支注册 | |||
- [[#208](https://github.com/apache/incubator-seata-go/pull/208)] 优化删除不必要代码 | |||
- [[#215](https://github.com/apache/incubator-seata-go/pull/215)] 优化使时间参数,提高可读性 | |||
- [[#179](https://github.com/apache/incubator-seata-go/pull/179)] 支持 TCC 一阶段传入用户自定义参数 | |||
- [[#198](https://github.com/apache/incubator-seata-go/pull/198)] 优化远程调用方法的传参 | |||
- [[#235](https://github.com/apache/incubator-seata-go/pull/235)] 调整 MessageType 枚举值命名规范 | |||
- [[#238](https://github.com/apache/incubator-seata-go/pull/238)] 添加一些待办事项注释,添加 hook 例子 | |||
- [[#261](https://github.com/apache/incubator-seata-go/pull/261)] 优化嵌套循环重试 | |||
- [[#284](https://github.com/apache/incubator-seata-go/pull/284)] 优化重试逻辑 | |||
- [[#286](https://github.com/apache/incubator-seata-go/pull/286)] 将 rm 和 tm 的初始化逻辑拆分 | |||
- [[#287](https://github.com/apache/incubator-seata-go/pull/287)] 重构 seata conn 逻辑 | |||
- [[#281](https://github.com/apache/incubator-seata-go/pull/281)] 优化全局事务使用 | |||
- [[#295](https://github.com/apache/incubator-seata-go/pull/295)] 重构 seata conn 逻辑 | |||
- [[#302](https://github.com/apache/incubator-seata-go/pull/302)] 修改 dubbo-go 版本 | |||
- [[#336](https://github.com/apache/incubator-seata-go/pull/336)] 优化 at 整体流程 | |||
- [[#346](https://github.com/apache/incubator-seata-go/pull/346)] 优化 at 事务提交流程 | |||
- [[#352](https://github.com/apache/incubator-seata-go/pull/352)] 优化获取元数据流程 | |||
- [[#354](https://github.com/apache/incubator-seata-go/pull/354)] 优化 at 事务提交流程 | |||
- [[#353](https://github.com/apache/incubator-seata-go/pull/353)] 修改方法接收者命名规范 | |||
- [[#356](https://github.com/apache/incubator-seata-go/pull/356)] 优化 at 事务回滚流程 | |||
### test: | |||
- [[#154](https://github.com/apache/incubator-seata-go/pull/154)] 添加 message 单元单测 | |||
- [[#163](https://github.com/apache/incubator-seata-go/pull/163)] 添加 tm 单元单测 | |||
- [[#203](https://github.com/apache/incubator-seata-go/pull/203)] 添加 getty 单元测试 | |||
- [[#204](https://github.com/apache/incubator-seata-go/pull/204)] 添加 dubbo filter 单元测试 | |||
- [[#210](https://github.com/apache/incubator-seata-go/pull/210)] 添加 Tcc 分支报告测试 | |||
- [[#192](https://github.com/apache/incubator-seata-go/pull/192)] 添加 rm 单元测试 | |||
- [[#229](https://github.com/apache/incubator-seata-go/pull/229)] 添加 common 单元测试 | |||
- [[#299](https://github.com/apache/incubator-seata-go/pull/299)] 添加 SQL Parser 单元测试 | |||
- [[#332](https://github.com/apache/incubator-seata-go/pull/332)] 添加 multi delete undo log 单元测试 | |||
- [[#358](https://github.com/apache/incubator-seata-go/pull/358)] 添加 AT 回滚的例子 | |||
### doc: | |||
- [[#202](https://github.com/apache/incubator-seata-go/pull/202)] 优化 github CI 流程,添加 condecov 、 issue CI 工作流 | |||
- [[#254](https://github.com/apache/incubator-seata-go/pull/254)] 添加自动检查 licence 的脚本 | |||
- [[#305](https://github.com/apache/incubator-seata-go/pull/305)] 修改 CI 不要自动关闭 issue 和 pr | |||
### contributors: | |||
非常感谢以下 contributors 的代码贡献。若有无意遗漏,请报告。 | |||
- [AlexStocks](https://github.com/AlexStocks) | |||
- [luky116](https://github.com/luky116) | |||
- [106umao](https://github.com/106umao) | |||
- [liiibpm](https://github.com/liiibpm) | |||
- [elrond-g](https://github.com/elrond-g) | |||
- [wang1309](https://github.com/wang1309) | |||
- [iSuperCoder](https://github.com/apache/incubator-seata-go/commits?author=iSuperCoder) | |||
- [a631807682](https://github.com/apache/incubator-seata-go/commits?author=a631807682) | |||
- [betterwinsone](https://github.com/apache/incubator-seata-go/commits?author=betterwinsone) | |||
- [jasondeng1997](https://github.com/apache/incubator-seata-go/commits?author=jasondeng1997) | |||
- [chuntaojun](https://github.com/apache/incubator-seata-go/commits?author=chuntaojun) | |||
- [complone](https://github.com/apache/incubator-seata-go/commits?author=complone) | |||
- [miaoxueyu](https://github.com/apache/incubator-seata-go/commits?author=miaoxueyu) | |||
- [PangXing](https://github.com/apache/incubator-seata-go/commits?author=PangXing) | |||
- [georgehao](https://github.com/apache/incubator-seata-go/commits?author=georgehao) | |||
- [baerwang](https://github.com/apache/incubator-seata-go/commits?author=baerwang) | |||
- [raspberry-hu](https://github.com/apache/incubator-seata-go/commits?author=raspberry-hu) | |||
- [WyattJia](https://github.com/apache/incubator-seata-go/commits?author=WyattJia) | |||
- [Code-Fight](https://github.com/Code-Fight) | |||
- [betterwinsone](https://github.com/betterwinsonet) | |||
同时,我们收到了社区反馈的很多有价值的issue和建议,非常感谢大家。 | |||
</detail> | |||
@@ -1,95 +0,0 @@ | |||
<!-- | |||
Licensed to the Apache Software Foundation (ASF) under one or more | |||
contributor license agreements. See the NOTICE file distributed with | |||
this work for additional information regarding copyright ownership. | |||
The ASF licenses this file to You under the Apache License, Version 2.0 | |||
(the "License"); you may not use this file except in compliance with | |||
the License. You may obtain a copy of the License at | |||
http://www.apache.org/licenses/LICENSE-2.0 | |||
Unless required by applicable law or agreed to in writing, software | |||
distributed under the License is distributed on an "AS IS" BASIS, | |||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
See the License for the specific language governing permissions and | |||
limitations under the License. | |||
--> | |||
### 1.0.3 | |||
<details> | |||
<summary><mark>Release notes</mark></summary> | |||
### Seata-go 1.0.3 | |||
Seata-go 1.0.3 Released. | |||
Seata-go is an easy-to-use, high-performance, open source distributed transaction solution. | |||
The version is updated as follows: | |||
### feature: | |||
- [[#380](https://github.com/apache/incubator-seata-go/pull/380)] support xa mysql connection | |||
- [[#383](https://github.com/apache/incubator-seata-go/pull/383)] support read tcc fence configuration file | |||
- [[#389](https://github.com/apache/incubator-seata-go/pull/389)] add the transaction id of xa mode | |||
- [[#398](https://github.com/apache/incubator-seata-go/pull/398)] support read TM configuration file | |||
- [[#399](https://github.com/apache/incubator-seata-go/pull/399)] support read getty configuration file | |||
- [[#405](https://github.com/apache/incubator-seata-go/pull/405)] support at mode insert on duplicate sql parsing | |||
- [[#406](https://github.com/apache/incubator-seata-go/pull/406)] support read transport configuration file | |||
- [[#410](https://github.com/apache/incubator-seata-go/pull/410)] support read undo log configuration file | |||
- [[#411](https://github.com/apache/incubator-seata-go/pull/411)] use tm's profile properties in the project | |||
- [[#412](https://github.com/apache/incubator-seata-go/pull/412)] support read rm configuration file | |||
- [[#412](https://github.com/apache/incubator-seata-go/pull/412)] support read service configuration file | |||
- [[#419](https://github.com/apache/incubator-seata-go/pull/419)] use undo-log's profile properties in the project | |||
### bugfix: | |||
- [[#387](https://github.com/apache/incubator-seata-go/pull/387)] fix loop recursion problem in OpenConnector | |||
- [[#401](https://github.com/apache/incubator-seata-go/pull/401)] fix branch register process | |||
- [[#418](https://github.com/apache/incubator-seata-go/pull/418)] fix the configuration file problem of undo log | |||
- [[#423](https://github.com/apache/incubator-seata-go/pull/423)] fix getty initialization failure | |||
- [[#424](https://github.com/apache/incubator-seata-go/pull/424)] fix getty initialization failure | |||
- [[#429](https://github.com/apache/incubator-seata-go/pull/429)] fix the problem of execution failure in at mode | |||
### optimize: | |||
- [[#366](https://github.com/apache/incubator-seata-go/pull/366)] add data check before rollbeck | |||
- [[#367](https://github.com/apache/incubator-seata-go/pull/367)] simplify to make codes more readable | |||
- [[#369](https://github.com/apache/incubator-seata-go/pull/369)] remove unless function | |||
- [[#385](https://github.com/apache/incubator-seata-go/pull/385)] optimize the SQL used in AT sample | |||
- [[#388](https://github.com/apache/incubator-seata-go/pull/388)] optimize comments and dead code | |||
- [[#390](https://github.com/apache/incubator-seata-go/pull/390)] optime rm init | |||
- [[#392](https://github.com/apache/incubator-seata-go/pull/392)] optimize code style | |||
- [[#394](https://github.com/apache/incubator-seata-go/pull/394)] optimize at mode base executor | |||
- [[#400](https://github.com/apache/incubator-seata-go/pull/400)] optime protocol init | |||
- [[#408](https://github.com/apache/incubator-seata-go/pull/408)] optime log init | |||
- [[#409](https://github.com/apache/incubator-seata-go/pull/409)] refactor logic of delete and insert sql in at mode | |||
- [[#414](https://github.com/apache/incubator-seata-go/pull/414)] rename unit test file | |||
- [[#422](https://github.com/apache/incubator-seata-go/pull/422)] remove unused config code | |||
### test: | |||
### doc: | |||
- [[#417](https://github.com/apache/incubator-seata-go/pull/417)] optiomize readme file | |||
### contributors: | |||
Thanks to these contributors for their code commits. Please report an unintended omission. | |||
- [AlexStocks](https://github.com/AlexStocks) | |||
- [luky116](https://github.com/luky116) | |||
- [georgehao](https://github.com/georgehao) | |||
- [lxfeng1997](https://github.com/lxfeng1997) | |||
- [106umao](https://github.com/106umao) | |||
- [liiibpm](https://github.com/liiibpm) | |||
- [wang1309](https://github.com/wang1309) | |||
- [iSuperCoder](https://github.com/iSuperCoder) | |||
- [jasondeng1997](https://github.com/jasondeng1997) | |||
- [Charlie17Li](https://github.com/Charlie17Li) | |||
- [Code-Fight](https://github.com/Code-Fight) | |||
- [Kirhaku](https://github.com/Kirhaku) | |||
Also, we receive many valuable issues, questions and advices from our community. Thanks all. | |||
</detail> |
@@ -1,98 +0,0 @@ | |||
<!-- | |||
Licensed to the Apache Software Foundation (ASF) under one or more | |||
contributor license agreements. See the NOTICE file distributed with | |||
this work for additional information regarding copyright ownership. | |||
The ASF licenses this file to You under the Apache License, Version 2.0 | |||
(the "License"); you may not use this file except in compliance with | |||
the License. You may obtain a copy of the License at | |||
http://www.apache.org/licenses/LICENSE-2.0 | |||
Unless required by applicable law or agreed to in writing, software | |||
distributed under the License is distributed on an "AS IS" BASIS, | |||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
See the License for the specific language governing permissions and | |||
limitations under the License. | |||
--> | |||
### 1.0.3 | |||
<details> | |||
<summary><mark>Release notes</mark></summary> | |||
### Seata-go 1.0.3 | |||
Seata-go 1.0.3 发布。 | |||
Seata-go 是一款开源的分布式事务解决方案,提供高性能和简单易用的分布式事务服务。 | |||
此版本更新如下: | |||
### feature: | |||
- [[#380](https://github.com/apache/incubator-seata-go/pull/380)] 支持 MySQL XA 的连接 | |||
- [[#383](https://github.com/apache/incubator-seata-go/pull/383)] 支持 TCC Fence 读取配置文件 | |||
- [[#389](https://github.com/apache/incubator-seata-go/pull/389)] 添加 XA 模式的事务ID | |||
- [[#398](https://github.com/apache/incubator-seata-go/pull/398)] 支持 TM 读取配置文件 | |||
- [[#399](https://github.com/apache/incubator-seata-go/pull/399)] 支持 getty 读取配置文件 | |||
- [[#405](https://github.com/apache/incubator-seata-go/pull/405)] 支持 AT 模式 insert on duplicate SQL 解析 | |||
- [[#406](https://github.com/apache/incubator-seata-go/pull/406)] 支持 transport 读取配置文件 | |||
- [[#410](https://github.com/apache/incubator-seata-go/pull/410)] 支持 undo log 读取配置文件 | |||
- [[#411](https://github.com/apache/incubator-seata-go/pull/411)] 在项目中使用 tm 的配置文件属性 | |||
- [[#412](https://github.com/apache/incubator-seata-go/pull/412)] 支持 RM 读取配置文件 | |||
- [[#413](https://github.com/apache/incubator-seata-go/pull/413)] 支持 service 读取配置文件 | |||
- [[#419](https://github.com/apache/incubator-seata-go/pull/419)] 在项目中使用 undo log 的配置文件属性 | |||
- [[#421](https://github.com/apache/incubator-seata-go/pull/421)] 支持 service 读取配置文件 | |||
### bugfix: | |||
- [[#387](https://github.com/apache/incubator-seata-go/pull/387)] 修复 OpenConnector 中死循环的问题 | |||
- [[#401](https://github.com/apache/incubator-seata-go/pull/401)] 优化注册事务分支的流程 | |||
- [[#418](https://github.com/apache/incubator-seata-go/pull/418)] 修复 undo log 的配置文件的问题 | |||
- [[#423](https://github.com/apache/incubator-seata-go/pull/423)] 修复 getty 初始化失败的问题 | |||
- [[#424](https://github.com/apache/incubator-seata-go/pull/424)] 修复 getty 初始化失败的问题 | |||
- [[#429](https://github.com/apache/incubator-seata-go/pull/429)] 修复 AT 模式执行失败的问题 | |||
### optimize: | |||
- [[#366](https://github.com/apache/incubator-seata-go/pull/366)] AT 回滚前添加数据校验逻辑 | |||
- [[#367](https://github.com/apache/incubator-seata-go/pull/367)] 优化 AT 代码的命名 | |||
- [[#369](https://github.com/apache/incubator-seata-go/pull/369)] 移除不用的方法 | |||
- [[#385](https://github.com/apache/incubator-seata-go/pull/385)] 优化 AT sample 的建表SQL | |||
- [[#388](https://github.com/apache/incubator-seata-go/pull/388)] 优化代码注释,删除不用的代码 | |||
- [[#390](https://github.com/apache/incubator-seata-go/pull/390)] 优化 RM 的初始化流程 | |||
- [[#392](https://github.com/apache/incubator-seata-go/pull/392)] 优化代码的风格问题 | |||
- [[#394](https://github.com/apache/incubator-seata-go/pull/394)] 重构 AT 模式的执行器 | |||
- [[#400](https://github.com/apache/incubator-seata-go/pull/400)] 优化 protocol 的初始化流程 | |||
- [[#408](https://github.com/apache/incubator-seata-go/pull/408)] 优化 log 的初始化流程 | |||
- [[#409](https://github.com/apache/incubator-seata-go/pull/409)] 重构 AT 模式的 delete 和 insert SQL 的执行逻辑 | |||
- [[#414](https://github.com/apache/incubator-seata-go/pull/414)] 重命名单测文件 | |||
- [[#422](https://github.com/apache/incubator-seata-go/pull/422)] 移除未使用的 config 代码 | |||
### test: | |||
### doc: | |||
- [[#417](https://github.com/apache/incubator-seata-go/pull/417)] 调整 readme 文件内容 | |||
### contributors: | |||
非常感谢以下 contributors 的代码贡献。若有无意遗漏,请报告。 | |||
- [AlexStocks](https://github.com/AlexStocks) | |||
- [luky116](https://github.com/luky116) | |||
- [georgehao](https://github.com/georgehao) | |||
- [lxfeng1997](https://github.com/lxfeng1997) | |||
- [106umao](https://github.com/106umao) | |||
- [liiibpm](https://github.com/liiibpm) | |||
- [wang1309](https://github.com/wang1309) | |||
- [iSuperCoder](https://github.com/iSuperCoder) | |||
- [jasondeng1997](https://github.com/jasondeng1997) | |||
- [Charlie17Li](https://github.com/Charlie17Li) | |||
- [Code-Fight](https://github.com/Code-Fight) | |||
- [Kirhaku](https://github.com/Kirhaku) | |||
同时,我们收到了社区反馈的很多有价值的issue和建议,非常感谢大家。 | |||
</detail> | |||
@@ -1,91 +0,0 @@ | |||
<!-- | |||
Licensed to the Apache Software Foundation (ASF) under one or more | |||
contributor license agreements. See the NOTICE file distributed with | |||
this work for additional information regarding copyright ownership. | |||
The ASF licenses this file to You under the Apache License, Version 2.0 | |||
(the "License"); you may not use this file except in compliance with | |||
the License. You may obtain a copy of the License at | |||
http://www.apache.org/licenses/LICENSE-2.0 | |||
Unless required by applicable law or agreed to in writing, software | |||
distributed under the License is distributed on an "AS IS" BASIS, | |||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
See the License for the specific language governing permissions and | |||
limitations under the License. | |||
--> | |||
### 1.1.0 | |||
<details> | |||
<summary><mark>Release notes</mark></summary> | |||
### Seata-go 1.1.0 | |||
Seata-go 1.1.0 Released. | |||
Seata-go is an easy-to-use, high-performance, open source distributed transaction solution. | |||
The version is updated as follows: | |||
### feature: | |||
- [[#491](https://github.com/apache/incubator-seata-go/pull/491)] support query global lock key | |||
- [[#482](https://github.com/apache/incubator-seata-go/pull/482)] support multi delete SQL executor in AT | |||
- [[#481](https://github.com/apache/incubator-seata-go/pull/481)] support multi update SQL executor in AT | |||
- [[#478](https://github.com/apache/incubator-seata-go/pull/478)] support select for update SQL executor in AT | |||
- [[#477](https://github.com/apache/incubator-seata-go/pull/477)] support the json serialization method of undo log | |||
- [[#456](https://github.com/apache/incubator-seata-go/pull/456)] support insert on update SQL executor in AT | |||
- [[#444](https://github.com/apache/incubator-seata-go/pull/444)] support BZip2Compressor | |||
- [[#436](https://github.com/apache/incubator-seata-go/pull/436)] use rm config file | |||
- [[#433](https://github.com/apache/incubator-seata-go/pull/433)] support xa connect manager | |||
- [[#430](https://github.com/apache/incubator-seata-go/pull/430)] use getty config file | |||
### bugfix: | |||
- [[#509](https://github.com/apache/incubator-seata-go/pull/509)] fix undo log SQLType when execute insert on update SQL in AT | |||
- [[#495](https://github.com/apache/incubator-seata-go/pull/495)] fix undo log SQLType bug | |||
- [[#487](https://github.com/apache/incubator-seata-go/pull/487)] fix at bug when execute | |||
- [[#472](https://github.com/apache/incubator-seata-go/pull/472)] fix missing value of context When using global transactions | |||
- [[#461](https://github.com/apache/incubator-seata-go/pull/461)] fix the problem of error_code_test | |||
- [[#459](https://github.com/apache/incubator-seata-go/pull/459)] fix the rollback error log | |||
- [[#452](https://github.com/apache/incubator-seata-go/pull/452)] fix the error of id self-increment when executing insert sql in AT | |||
### optimize: | |||
- [[#507](https://github.com/apache/incubator-seata-go/pull/507)] refactor logic of multiple update sql in AT | |||
- [[#505](https://github.com/apache/incubator-seata-go/pull/505)] optimize multi SQL executor in AT | |||
- [[#453](https://github.com/apache/incubator-seata-go/pull/453)] optimize the messageType and transactionErrorCode enum | |||
- [[#447](https://github.com/apache/incubator-seata-go/pull/447)] optimize the datasource init process | |||
- [[#466](https://github.com/apache/incubator-seata-go/pull/466)] optimize variable naming | |||
### test: | |||
- [[#445](https://github.com/apache/incubator-seata-go/pull/445)] add unit test for TransactionErrorCode and MessageType | |||
### doc: | |||
- [[#492](https://github.com/apache/incubator-seata-go/pull/492)] update feature list of readme | |||
- [[#489](https://github.com/apache/incubator-seata-go/pull/489)] add change-log of version 1.1.0 | |||
### contributors: | |||
Thanks to these contributors for their code commits. Please report an unintended omission. | |||
- [luky116](https://github.com/luky116) | |||
- [georgehao](https://github.com/georgehao) | |||
- [lxfeng1997](https://github.com/lxfeng1997) | |||
- [106umao](https://github.com/106umao) | |||
- [wang1309](https://github.com/wang1309) | |||
- [iSuperCoder](https://github.com/iSuperCoder) | |||
- [Charlie17Li](https://github.com/Charlie17Li) | |||
- [Code-Fight](https://github.com/Code-Fight) | |||
- [Kirhaku](https://github.com/Kirhaku) | |||
- [Vaderkai](https://github.com/VaderKai) | |||
- [springrain](https://github.com/springrain) | |||
- [Shaozhou Hu](https://github.com/raspberry-hu) | |||
- [finkyky](https://github.com/Finkyky) | |||
Also, we receive many valuable issues, questions and advices from our community. Thanks all. | |||
</detail> |
@@ -1,92 +0,0 @@ | |||
<!-- | |||
Licensed to the Apache Software Foundation (ASF) under one or more | |||
contributor license agreements. See the NOTICE file distributed with | |||
this work for additional information regarding copyright ownership. | |||
The ASF licenses this file to You under the Apache License, Version 2.0 | |||
(the "License"); you may not use this file except in compliance with | |||
the License. You may obtain a copy of the License at | |||
http://www.apache.org/licenses/LICENSE-2.0 | |||
Unless required by applicable law or agreed to in writing, software | |||
distributed under the License is distributed on an "AS IS" BASIS, | |||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
See the License for the specific language governing permissions and | |||
limitations under the License. | |||
--> | |||
### 1.1.0 | |||
<details> | |||
<summary><mark>Release notes</mark></summary> | |||
### Seata-go 1.1.0 | |||
Seata-go 1.1.0 发布。 | |||
Seata-go 是一款开源的分布式事务解决方案,提供高性能和简单易用的分布式事务服务。 | |||
此版本更新如下: | |||
### feature: | |||
- [[#491](https://github.com/apache/incubator-seata-go/pull/491)] 支持查询全局事务锁 | |||
- [[#482](https://github.com/apache/incubator-seata-go/pull/482)] 支持 AT 模式 multi delete SQL 执行器 | |||
- [[#481](https://github.com/apache/incubator-seata-go/pull/481)] 支持 AT 模式 multi update SQL 执行器 | |||
- [[#478](https://github.com/apache/incubator-seata-go/pull/478)] 支持 AT 模式 select for update SQL 执行器 | |||
- [[#477](https://github.com/apache/incubator-seata-go/pull/477)] 支持 undo log 的 json 序列化方式 | |||
- [[#456](https://github.com/apache/incubator-seata-go/pull/456)] 支持 AT 模式 insert on update SQL 执行器 | |||
- [[#444](https://github.com/apache/incubator-seata-go/pull/444)] 支持 BZip 压缩算法 | |||
- [[#436](https://github.com/apache/incubator-seata-go/pull/436)] 支持读取 rm 相关的配置文件 | |||
- [[#433](https://github.com/apache/incubator-seata-go/pull/433)] 支持 xa 连接管理 | |||
- [[#430](https://github.com/apache/incubator-seata-go/pull/430)] 支持读取 getty 相关的配置文件 | |||
### bugfix: | |||
- [[#509](https://github.com/apache/incubator-seata-go/pull/509)] 修复 AT 模式下执行 insert on update 时 undo log 的 SQLType 字段的问题 | |||
- [[#495](https://github.com/apache/incubator-seata-go/pull/495)] 修复 undo log 的 SQLType 字段的问题 | |||
- [[#487](https://github.com/apache/incubator-seata-go/pull/487)] 修复 AT 执行时出现的问题 | |||
- [[#472](https://github.com/apache/incubator-seata-go/pull/472)] 修复全局事务中上下文丢失值问题 | |||
- [[#461](https://github.com/apache/incubator-seata-go/pull/461)] 修复 error_code_test 中变量未定义导致的 ci 失败问题 | |||
- [[#459](https://github.com/apache/incubator-seata-go/pull/459)] 修复 error 日志重复打印问题 | |||
- [[#452](https://github.com/apache/incubator-seata-go/pull/452)] 修复 AT 模式 执行 insert SQL 时 id 自增的报错问题 | |||
### optimize: | |||
- [[#507](https://github.com/apache/incubator-seata-go/pull/507)] 优化 AT 模式 multiple update SQL 执行器 | |||
- [[#505](https://github.com/apache/incubator-seata-go/pull/505)] 优化 AT 模式 multi SQL 执行器 | |||
- [[#453](https://github.com/apache/incubator-seata-go/pull/453)] 优化 messageType 和 transactionErrorCode 枚举值 | |||
- [[#447](https://github.com/apache/incubator-seata-go/pull/447)] 优化数据源初始化流程 | |||
- [[#466](https://github.com/apache/incubator-seata-go/pull/466)] 优化变量的命名 | |||
### test: | |||
- [[#445](https://github.com/apache/incubator-seata-go/pull/445)] 添加 TransactionErrorCode 的单元测试 | |||
### doc: | |||
- [[#492](https://github.com/apache/incubator-seata-go/pull/492)] 更新 readme 文件的已完成功能列表 | |||
- [[#489](https://github.com/apache/incubator-seata-go/pull/489)] 添加 1.1.0 版本的 change log | |||
### contributors: | |||
非常感谢以下 contributors 的代码贡献。若有无意遗漏,请报告。 | |||
- [luky116](https://github.com/luky116) | |||
- [georgehao](https://github.com/georgehao) | |||
- [lxfeng1997](https://github.com/lxfeng1997) | |||
- [106umao](https://github.com/106umao) | |||
- [wang1309](https://github.com/wang1309) | |||
- [iSuperCoder](https://github.com/iSuperCoder) | |||
- [Charlie17Li](https://github.com/Charlie17Li) | |||
- [Code-Fight](https://github.com/Code-Fight) | |||
- [Kirhaku](https://github.com/Kirhaku) | |||
- [Vaderkai](https://github.com/VaderKai) | |||
- [springrain](https://github.com/springrain) | |||
- [Shaozhou Hu](https://github.com/raspberry-hu) | |||
- [finkyky](https://github.com/Finkyky) | |||
同时,我们收到了社区反馈的很多有价值的issue和建议,非常感谢大家。 | |||
</detail> | |||
@@ -1,80 +0,0 @@ | |||
<!-- | |||
Licensed to the Apache Software Foundation (ASF) under one or more | |||
contributor license agreements. See the NOTICE file distributed with | |||
this work for additional information regarding copyright ownership. | |||
The ASF licenses this file to You under the Apache License, Version 2.0 | |||
(the "License"); you may not use this file except in compliance with | |||
the License. You may obtain a copy of the License at | |||
http://www.apache.org/licenses/LICENSE-2.0 | |||
Unless required by applicable law or agreed to in writing, software | |||
distributed under the License is distributed on an "AS IS" BASIS, | |||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
See the License for the specific language governing permissions and | |||
limitations under the License. | |||
--> | |||
### 1.2.0 | |||
<details> | |||
<summary><mark>Release notes</mark></summary> | |||
### Seata-go 1.2.0 | |||
Seata-go 1.2.0 Released. | |||
Seata-go is an easy-to-use, high-performance, open source distributed transaction solution. | |||
The version is updated as follows: | |||
### feature: | |||
- [[#534](https://github.com/apache/incubator-seata-go/pull/534)] support session load balance | |||
- [[#535](https://github.com/apache/incubator-seata-go/pull/535)] add integrate test | |||
### bugfix: | |||
- [[#540](https://github.com/apache/incubator-seata-go/pull/540)] fix init xa panic bug | |||
- [[#545](https://github.com/apache/incubator-seata-go/pull/545)] fix get db version bug | |||
- [[#548](https://github.com/apache/incubator-seata-go/pull/548)] fix start xa failed bug | |||
- [[#556](https://github.com/apache/incubator-seata-go/pull/556)] fix start xa driver failed bug | |||
- [[#562](https://github.com/apache/incubator-seata-go/pull/562)] fix commit xa panic bug | |||
- [[#564](https://github.com/apache/incubator-seata-go/pull/564)] fix commit xa branch bug | |||
- [[#566](https://github.com/apache/incubator-seata-go/pull/566)] fix execute local tx bug | |||
### optimize: | |||
- [[#523](https://github.com/apache/incubator-seata-go/pull/523)] optimize the golang ci lint | |||
- [[#525](https://github.com/apache/incubator-seata-go/pull/456)] rename parser name from jackson to json | |||
- [[#532](https://github.com/apache/incubator-seata-go/pull/532)] remove duplicate code | |||
- [[#536](https://github.com/apache/incubator-seata-go/pull/536)] format go import | |||
- [[#554](https://github.com/apache/incubator-seata-go/pull/554)] optimize the performance of XA transactions | |||
- [[#561](https://github.com/apache/incubator-seata-go/pull/561)] optimize xa output log | |||
### test: | |||
### doc: | |||
- [[#550](https://github.com/apache/incubator-seata-go/pull/550)] add change-log of version 1.2.0 | |||
### contributors: | |||
Thanks to these contributors for their code commits. Please report an unintended omission. | |||
- [georgehao](https://github.com/georgehao) | |||
- [luky116](https://github.com/luky116) | |||
- [jasondeng1997](https://github.com/jasondeng1997) | |||
- [106umao](https://github.com/106umao) | |||
- [wang1309](https://github.com/wang1309) | |||
- [iSuperCoder](https://github.com/iSuperCoder) | |||
- [Charlie17Li](https://github.com/Charlie17Li) | |||
- [Code-Fight](https://github.com/Code-Fight) | |||
- [Kirhaku](https://github.com/Kirhaku) | |||
- [Vaderkai](https://github.com/VaderKai) | |||
Also, we receive many valuable issues, questions and advices from our community. Thanks all. | |||
</detail> |
@@ -1,83 +0,0 @@ | |||
<!-- | |||
Licensed to the Apache Software Foundation (ASF) under one or more | |||
contributor license agreements. See the NOTICE file distributed with | |||
this work for additional information regarding copyright ownership. | |||
The ASF licenses this file to You under the Apache License, Version 2.0 | |||
(the "License"); you may not use this file except in compliance with | |||
the License. You may obtain a copy of the License at | |||
http://www.apache.org/licenses/LICENSE-2.0 | |||
Unless required by applicable law or agreed to in writing, software | |||
distributed under the License is distributed on an "AS IS" BASIS, | |||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
See the License for the specific language governing permissions and | |||
limitations under the License. | |||
--> | |||
### 1.2.0 | |||
<details> | |||
<summary><mark>Release notes</mark></summary> | |||
### Seata-go 1.2.0 | |||
Seata-go 1.2.0 发布。 | |||
Seata-go 是一款开源的分布式事务解决方案,提供高性能和简单易用的分布式事务服务。 | |||
此版本更新如下: | |||
### feature: | |||
- [[#534](https://github.com/apache/incubator-seata-go/pull/534)] 支持 session 的负载均衡 | |||
- [[#535](https://github.com/apache/incubator-seata-go/pull/535)] 添加加成测试 | |||
### bugfix: | |||
- [[#540](https://github.com/apache/incubator-seata-go/pull/540)] 修复初始化 xa 模式的 bug | |||
- [[#545](https://github.com/apache/incubator-seata-go/pull/545)] 修复 xa 模式获取 db 版本号的 bug | |||
- [[#548](https://github.com/apache/incubator-seata-go/pull/548)] 修复启动 xa 时候会失败的 bug | |||
- [[#556](https://github.com/apache/incubator-seata-go/pull/556)] 修复 xa 数据源的 bug | |||
- [[#562](https://github.com/apache/incubator-seata-go/pull/562)] 修复提交 xa 全局事务的 bug | |||
- [[#564](https://github.com/apache/incubator-seata-go/pull/564)] 修复提交 xa 分支事务的 bug | |||
- [[#566](https://github.com/apache/incubator-seata-go/pull/566)] 修复使用 xa 数据源执行本地事务的 bug | |||
### optimize: | |||
- [[#523](https://github.com/apache/incubator-seata-go/pull/523)] 优化 CI 流程 | |||
- [[#525](https://github.com/apache/incubator-seata-go/pull/456)] 将 jackson 序列化重命名为 json | |||
- [[#532](https://github.com/apache/incubator-seata-go/pull/532)] 移除重复的代码 | |||
- [[#536](https://github.com/apache/incubator-seata-go/pull/536)] 优化 go import 代码格式 | |||
- [[#554](https://github.com/apache/incubator-seata-go/pull/554)] 优化 xa 模式的性能 | |||
- [[#561](https://github.com/apache/incubator-seata-go/pull/561)] 优化 xa 模式的日志输出 | |||
### test: | |||
### doc: | |||
- [[#550](https://github.com/apache/incubator-seata-go/pull/550)] 添加 1.2.0 版本的改动日志 | |||
### contributors: | |||
非常感谢以下 contributors 的代码贡献。若有无意遗漏,请报告。 | |||
- [georgehao](https://github.com/georgehao) | |||
- [luky116](https://github.com/luky116) | |||
- [jasondeng1997](https://github.com/jasondeng1997) | |||
- [106umao](https://github.com/106umao) | |||
- [wang1309](https://github.com/wang1309) | |||
- [iSuperCoder](https://github.com/iSuperCoder) | |||
- [Charlie17Li](https://github.com/Charlie17Li) | |||
- [Code-Fight](https://github.com/Code-Fight) | |||
- [Kirhaku](https://github.com/Kirhaku) | |||
- [Vaderkai](https://github.com/VaderKai) | |||
同时,我们收到了社区反馈的很多有价值的issue和建议,非常感谢大家。 | |||
</detail> | |||
@@ -1,173 +0,0 @@ | |||
<!-- | |||
Licensed to the Apache Software Foundation (ASF) under one or more | |||
contributor license agreements. See the NOTICE file distributed with | |||
this work for additional information regarding copyright ownership. | |||
The ASF licenses this file to You under the Apache License, Version 2.0 | |||
(the "License"); you may not use this file except in compliance with | |||
the License. You may obtain a copy of the License at | |||
http://www.apache.org/licenses/LICENSE-2.0 | |||
Unless required by applicable law or agreed to in writing, software | |||
distributed under the License is distributed on an "AS IS" BASIS, | |||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
See the License for the specific language governing permissions and | |||
limitations under the License. | |||
--> | |||
### 2.0.0 | |||
<details> | |||
<summary><mark>Release notes</mark></summary> | |||
### Seata-go 2.0.0 | |||
Seata-go 2.0.0 Released. | |||
Seata-go is an easy-to-use, high-performance, open source distributed transaction solution. | |||
The version is updated as follows: | |||
### feature: | |||
- [[#761](https://github.com/apache/incubator-seata-go/pull/761)]Support Update join | |||
- [[#806](https://github.com/apache/incubator-seata-go/pull/806)]Add Release Drafter configuration files | |||
- [[#659](https://github.com/apache/incubator-seata-go/pull/659)] support compress for AT undo log | |||
- [[#574](https://github.com/apache/incubator-seata-go/pull/574)] support file and nacos service registry | |||
- [[#584](https://github.com/apache/incubator-seata-go/pull/584)] support the ConsistentHash load balancing strategy in the remoting module | |||
- [[#585](https://github.com/apache/incubator-seata-go/pull/585)] support the LeastActive load balancing strategy in the remoting module | |||
- [[#605](https://github.com/apache/incubator-seata-go/pull/605)] support the discovery service of Etcd | |||
- [[#622](https://github.com/apache/incubator-seata-go/pull/622)] add round robin strategy of remote call | |||
- [[#691](https://github.com/apache/incubator-seata-go/pull/691)] support protobuf undo log parser | |||
- [[#738](https://github.com/apache/incubator-seata-go/pull/738)] remove session when send heart beat message failed | |||
- [[#739](https://github.com/apache/incubator-seata-go/pull/739)] support automatic refresh functionality for table meta cache | |||
### bugfix: | |||
- [[#877](https://github.com/apache/incubator-seata-go/pull/857)]del metadatacache uppertablenamekey and increase tablemeta field uppertablename | |||
- [[#861](https://github.com/apache/incubator-seata-go/pull/861)]update project icon in readme | |||
- [[#834](https://github.com/apache/incubator-seata-go/pull/834)]Solve the conflict problem of introducing multiple versions of knadh | |||
- [[#839](https://github.com/apache/incubator-seata-go/pull/839)]fix action errors | |||
- [[#850](https://github.com/apache/incubator-seata-go/pull/850)]fix failed parsing table of delete sql | |||
- [[#823](https://github.com/apache/incubator-seata-go/pull/823)]Remove issue translation workflow | |||
- [[#820](https://github.com/apache/incubator-seata-go/pull/820)]Fix possible vulnerabilities caused by common libraries | |||
- [[#810](https://github.com/apache/incubator-seata-go/pull/810)]fix transaction failed ,when using queryContext | |||
- [[#813](https://github.com/apache/incubator-seata-go/pull/813)]add some licenser header | |||
- [[#771](https://github.com/apache/incubator-seata-go/pull/771)]mysql insert on update duplicate sensitive case not matched | |||
- [[#797](https://github.com/apache/incubator-seata-go/pull/797)] add ASF header to some files | |||
- [[#781](https://github.com/apache/incubator-seata-go/pull/781)] Fixed that the same record has different lowkeys due to mixed case of table names | |||
- [[#780](https://github.com/apache/incubator-seata-go/pull/780)] failed to decode ColumnImage mysql:text type by json | |||
- [[#782](https://github.com/apache/incubator-seata-go/pull/782)] failed to decode ColumnImage mysql:text type by json | |||
- [[#789](https://github.com/apache/incubator-seata-go/pull/789)] add 2025 to NOTICE | |||
- [[#776](https://github.com/apache/incubator-seata-go/pull/776)] fix ci-lint typecheck error | |||
- [[#540](https://github.com/apache/incubator-seata-go/pull/540)] fix init XA panic bug | |||
- [[#590](https://github.com/apache/incubator-seata-go/pull/590)] fix some repo error | |||
- [[#595](https://github.com/apache/incubator-seata-go/pull/595)] check the response error is nil for commit or rollback | |||
- [[#607](https://github.com/apache/incubator-seata-go/pull/607)] fix the bug of jackson serialize | |||
- [[#665](https://github.com/apache/incubator-seata-go/pull/665)] reclaim the heartbeat response message to avoid memory leakage of GettyRemoting.future | |||
- [[#672](https://github.com/apache/incubator-seata-go/pull/672)] fix AT rollback bug | |||
- [[#674](https://github.com/apache/incubator-seata-go/pull/674)] fix XA rollback bug | |||
- [[#690](https://github.com/apache/incubator-seata-go/pull/690)] fix AT undo log jackson parser not found bug | |||
- [[#701](https://github.com/apache/incubator-seata-go/pull/701)] fix the InsertOnDuplicateUpdate is an issue with bypassing modifying the primary key | |||
- [[#717](https://github.com/apache/incubator-seata-go/pull/717)] support XA report state to TC | |||
- [[#724](https://github.com/apache/incubator-seata-go/pull/724)] support ParenthesesExpr for SQL parser | |||
- [[#736](https://github.com/apache/incubator-seata-go/pull/736)] fix SQL statement not closed's bug | |||
- [[#743](https://github.com/apache/incubator-seata-go/pull/743)] fix bug of gomonkey | |||
- [[#749](https://github.com/apache/incubator-seata-go/pull/749)] fix bug of heart beat | |||
### optimize: | |||
- [[#837](https://github.com/apache/incubator-seata-go/pull/837)]AT model optimize build lock key performance | |||
- [[#824](https://github.com/apache/incubator-seata-go/pull/824)]update SHA256 checksum command in makefile for cross-platform compatibility | |||
- [[#777](https://github.com/apache/incubator-seata-go/pull/777)]optimize transaction timeout judgment | |||
- [[#786](https://github.com/apache/incubator-seata-go/pull/786)]support ipv6 | |||
- [[#802](https://github.com/apache/incubator-seata-go/pull/802)]support get db version in conn | |||
- [[#745](https://github.com/apache/incubator-seata-go/pull/745)]optimized the daily deletion of fence logs | |||
- [[#767](https://github.com/apache/incubator-seata-go/pull/767)]upgrade some dependent packages to eliminate dependencies on some archived repositories | |||
- [[#768](https://github.com/apache/incubator-seata-go/pull/768)]update parser to v0.2.17 | |||
- [[#576](https://github.com/apache/incubator-seata-go/pull/576)] use mirromutth/mysql-action instead of icomponent/mysql-action | |||
- [[#594](https://github.com/apache/incubator-seata-go/pull/594)] optimize the log of branch commit procesor | |||
- [[#621](https://github.com/apache/incubator-seata-go/pull/621)] add codeql for ci | |||
- [[#631](https://github.com/apache/incubator-seata-go/pull/631)] upgrade crypto version from 0.9.0 to 0.17.0 | |||
- [[#652](https://github.com/apache/incubator-seata-go/pull/652)] upgrade gRPC version from 1.51.0 ro 1.56.3 | |||
- [[#667](https://github.com/apache/incubator-seata-go/pull/667)] change mailbox of issues and pull requests from dev to notifications | |||
- [[#678](https://github.com/apache/incubator-seata-go/pull/678)] rename module name to seata.apache.org/seata-go | |||
- [[#679](https://github.com/apache/incubator-seata-go/pull/679)] upgrade getty version from 1.4.9 to 1.4.10 | |||
- [[#714](https://github.com/apache/incubator-seata-go/pull/714)] optimize the speed of build lock key | |||
- [[#719](https://github.com/apache/incubator-seata-go/pull/719)] only save insertd filed when execute insert SQL in AT | |||
- [[#721](https://github.com/apache/incubator-seata-go/pull/721)] fix the issue where the translation bot is not working | |||
- [[#758](https://github.com/apache/incubator-seata-go/pull/758)] remove unusen files | |||
### test: | |||
- [[#570](https://github.com/apache/incubator-seata-go/pull/570)] add collection unit test | |||
- [[#571](https://github.com/apache/incubator-seata-go/pull/571)] add convert unit test | |||
- [[#572](https://github.com/apache/incubator-seata-go/pull/572)] add reflectx unit test | |||
- [[#5835f0](https://github.com/apache/incubator-seata-go/commit/5835f09ecfd6edeb04c2961163bc4460f578e942)] add random loadbalance unit test | |||
- [[#599](https://github.com/apache/incubator-seata-go/pull/599)] add xid loadbalance unit test | |||
### doc: | |||
- [[#844](https://github.com/apache/incubator-seata-go/pull/844)]Enrich the project ReadMe | |||
- [[#760](https://github.com/apache/incubator-seata-go/pull/760)]V2.0.0 release updater | |||
- [[#614](https://github.com/apache/incubator-seata-go/pull/614)] upgrade the unknown license dependency | |||
- [[#632](https://github.com/apache/incubator-seata-go/pull/632)] add ASF basic config | |||
- [[#633](https://github.com/apache/incubator-seata-go/pull/633)] optimize ASF basic config to remove th context check | |||
- [[#644](https://github.com/apache/incubator-seata-go/pull/644)] optimize readme file | |||
- [[#686](https://github.com/apache/incubator-seata-go/pull/686)] add more linter in ci | |||
- [[#737](https://github.com/apache/incubator-seata-go/pull/737)] modify the readme file and update the currently completed work | |||
- [[#756](https://github.com/apache/incubator-seata-go/pull/756)] update license checker | |||
### contributors: | |||
Thanks to these contributors for their code commits. Please report an unintended omission. | |||
- [luky116](https://github.com/luky116) | |||
- [Code-Fight](https://github.com/Code-Fight) | |||
- [wt-better](https://github.com/wt-better) | |||
- [luweiqianyi](https://github.com/luweiqianyi) | |||
- [wang1309](https://github.com/wang1309) | |||
- [576470954](https://github.com/576470954) | |||
- [No-SilverBullet](https://github.com/No-SilverBullet) | |||
- [solisamicus](https://github.com/solisamicus) | |||
- [marsevilspirit](https://github.com/marsevilspirit) | |||
- [lxfeng1997](https://github.com/lxfeng1997) | |||
- [AlexStocks](https://github.com/AlexStocks) | |||
- [smiletrl](https://github.com/smiletrl) | |||
- [ptyin](https://github.com/ptyin) | |||
- [yizhibian](https://github.com/yizhibian) | |||
- [oldmee](https://github.com/oldmee) | |||
- [air-3](https://github.com/air-3) | |||
- [slievrly](https://github.com/slievrly) | |||
- [xjlgod](https://github.com/xjlgod) | |||
- [baerwang](https://github.com/baerwang) | |||
- [xyombo](https://github.com/xyombo) | |||
- [testwill](https://github.com/testwill) | |||
- [jasondeng1997](https://github.com/jasondeng1997) | |||
- [jsbxyyx](https://github.com/jsbxyyx) | |||
- [iSuperCoder](https://github.com/iSuperCoder) | |||
- [georgehao](https://github.com/georgehao) | |||
- [liuyuecai](https://github.com/liuyuecai) | |||
- [106umao](https://github.com/106umao) | |||
- [FinnTew](https://github.com/FinnTew) | |||
- [funky-eyes](https://github.com/funky-eyes) | |||
- [tanzegen](https://github.com/tanzegen) | |||
- [lovepoem](https://github.com/lovepoem) | |||
- [MinatoWu](https://github.com/MinatoWu) | |||
- [LucienShen-Liu](https://github.com/LucienShen-Liu) | |||
- [panlei-coder](https://github.com/panlei-coder) | |||
- [lixingjia77](https://github.com/lixingjia77) | |||
- [Road2Melon](https://github.com/Road2Melon) | |||
- [Similarityoung](https://github.com/Similarityoung) | |||
- [YvCeung](https://github.com/YvCeung) | |||
- [pjfanning](https://github.com/pjfanning) | |||
- [hokkine](https://github.com/hokkine) | |||
- [zhangymPerson](https://github.com/zhangymPerson) | |||
- [ForestLH](https://github.com/ForestLH) | |||
Also, we receive many valuable issues, questions and advices from our community. Thanks all. | |||
</detail> |
@@ -1,169 +0,0 @@ | |||
<!-- | |||
Licensed to the Apache Software Foundation (ASF) under one or more | |||
contributor license agreements. See the NOTICE file distributed with | |||
this work for additional information regarding copyright ownership. | |||
The ASF licenses this file to You under the Apache License, Version 2.0 | |||
(the "License"); you may not use this file except in compliance with | |||
the License. You may obtain a copy of the License at | |||
http://www.apache.org/licenses/LICENSE-2.0 | |||
Unless required by applicable law or agreed to in writing, software | |||
distributed under the License is distributed on an "AS IS" BASIS, | |||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
See the License for the specific language governing permissions and | |||
limitations under the License. | |||
--> | |||
### 2.0.0 | |||
<details> | |||
<summary><mark>版本变更</mark></summary> | |||
# Seata-go 2.0.0 | |||
Seata-go 2.0.0 已发布。 | |||
Seata-go 是一个易于使用、高性能的开源分布式事务解决方案。 | |||
本版本更新内容如下: | |||
## 新增特性(feature): | |||
- [[#761](https://github.com/apache/incubator-seata-go/pull/761)] 支持 Update join。 | |||
- [[#806](https://github.com/apache/incubator-seata-go/pull/806)] 新增 Release Drafter 配置文件。 | |||
- [[#659](https://github.com/apache/incubator-seata-go/pull/659)] 为 AT undo log 支持压缩。 | |||
- [[#574](https://github.com/apache/incubator-seata-go/pull/574)] 支持基于文件(file)和 Nacos 的服务注册。 | |||
- [[#584](https://github.com/apache/incubator-seata-go/pull/584)] 在 remoting 模块中支持 ConsistentHash 负载均衡策略。 | |||
- [[#585](https://github.com/apache/incubator-seata-go/pull/585)] 在 remoting 模块中支持 LeastActive 负载均衡策略。 | |||
- [[#605](https://github.com/apache/incubator-seata-go/pull/605)] 支持 Etcd 的服务发现。 | |||
- [[#622](https://github.com/apache/incubator-seata-go/pull/622)] 为远程调用新增轮询(round robin)策略。 | |||
- [[#691](https://github.com/apache/incubator-seata-go/pull/691)] 支持 protobuf 格式的 undo log 解析器。 | |||
- [[#738](https://github.com/apache/incubator-seata-go/pull/738)] 在发送心跳消息失败时移除会话。 | |||
- [[#739](https://github.com/apache/incubator-seata-go/pull/739)] 支持表元数据缓存的自动刷新功能。 | |||
## 修复(bugfix): | |||
- [[#877](https://github.com/apache/incubator-seata-go/pull/857)] 删除 metadatacache 的 uppertablenamekey,并在 tablemeta 中增加 uppertablename 字段。 | |||
- [[#861](https://github.com/apache/incubator-seata-go/pull/861)] 更新 README 中的项目图标。 | |||
- [[#834](https://github.com/apache/incubator-seata-go/pull/834)] 解决引入多个版本 knadh 导致的冲突问题。 | |||
- [[#839](https://github.com/apache/incubator-seata-go/pull/839)] 修复 Action 错误。 | |||
- [[#850](https://github.com/apache/incubator-seata-go/pull/850)] 修复删除类 SQL 的表解析失败问题。 | |||
- [[#823](https://github.com/apache/incubator-seata-go/pull/823)] 移除 issue 翻译工作流。 | |||
- [[#820](https://github.com/apache/incubator-seata-go/pull/820)] 修复由通用库引起的潜在安全漏洞。 | |||
- [[#810](https://github.com/apache/incubator-seata-go/pull/810)] 修复在使用 queryContext 时导致事务失败的问题。 | |||
- [[#813](https://github.com/apache/incubator-seata-go/pull/813)] 为若干文件添加许可头。 | |||
- [[#771](https://github.com/apache/incubator-seata-go/pull/771)] 修复 MySQL `INSERT ... ON DUPLICATE UPDATE` 在大小写敏感场景下匹配不正确的问题。 | |||
- [[#797](https://github.com/apache/incubator-seata-go/pull/797)] 为部分文件添加 ASF 头。 | |||
- [[#781](https://github.com/apache/incubator-seata-go/pull/781)] 修复因表名大小写混合导致相同记录出现不同 lowkeys 的问题。 | |||
- [[#780](https://github.com/apache/incubator-seata-go/pull/780)] 修复无法通过 JSON 解码 MySQL `TEXT` 类型的 ColumnImage 的问题。 | |||
- [[#782](https://github.com/apache/incubator-seata-go/pull/782)] 修复无法通过 JSON 解码 MySQL `TEXT` 类型的 ColumnImage 的问题(重复修复项)。 | |||
- [[#789](https://github.com/apache/incubator-seata-go/pull/789)] 在 NOTICE 中添加 2025 年。 | |||
- [[#776](https://github.com/apache/incubator-seata-go/pull/776)] 修复 CI lint 类型检查错误。 | |||
- [[#540](https://github.com/apache/incubator-seata-go/pull/540)] 修复初始化 XA 时的 panic 错误。 | |||
- [[#590](https://github.com/apache/incubator-seata-go/pull/590)] 修复若干仓库错误。 | |||
- [[#595](https://github.com/apache/incubator-seata-go/pull/595)] 在提交(commit)或回滚(rollback)时检查响应错误是否为 nil。 | |||
- [[#607](https://github.com/apache/incubator-seata-go/pull/607)] 修复 Jackson 序列化的相关 bug。 | |||
- [[#665](https://github.com/apache/incubator-seata-go/pull/665)] 回收心跳响应消息,以避免 GettyRemoting.future 的内存泄漏。 | |||
- [[#672](https://github.com/apache/incubator-seata-go/pull/672)] 修复 AT 回滚的错误。 | |||
- [[#674](https://github.com/apache/incubator-seata-go/pull/674)] 修复 XA 回滚的错误。 | |||
- [[#690](https://github.com/apache/incubator-seata-go/pull/690)] 修复 AT undo log 的 Jackson 解析器未找到的问题。 | |||
- [[#701](https://github.com/apache/incubator-seata-go/pull/701)] 修复 InsertOnDuplicateUpdate 绕过主键修改所导致的问题。 | |||
- [[#717](https://github.com/apache/incubator-seata-go/pull/717)] 支持 XA 向 TC 报告状态。 | |||
- [[#724](https://github.com/apache/incubator-seata-go/pull/724)] 为 SQL 解析器支持 ParenthesesExpr(括号表达式)。 | |||
- [[#736](https://github.com/apache/incubator-seata-go/pull/736)] 修复 SQL 语句未正确关闭的问题。 | |||
- [[#743](https://github.com/apache/incubator-seata-go/pull/743)] 修复 gomonkey 相关的 bug。 | |||
- [[#749](https://github.com/apache/incubator-seata-go/pull/749)] 修复心跳相关的 bug。 | |||
## 优化(optimize): | |||
- [[#837](https://github.com/apache/incubator-seata-go/pull/837)] 优化 AT 模型中构建锁键的性能。 | |||
- [[#824](https://github.com/apache/incubator-seata-go/pull/824)] 更新 Makefile 中的 SHA256 校验命令以兼容跨平台。 | |||
- [[#777](https://github.com/apache/incubator-seata-go/pull/777)] 优化事务超时判断逻辑。 | |||
- [[#786](https://github.com/apache/incubator-seata-go/pull/786)] 支持 IPv6。 | |||
- [[#802](https://github.com/apache/incubator-seata-go/pull/802)] 在连接中支持获取数据库版本。 | |||
- [[#745](https://github.com/apache/incubator-seata-go/pull/745)] 优化 fence 日志的每日删除策略。 | |||
- [[#767](https://github.com/apache/incubator-seata-go/pull/767)] 升级若干依赖包以消除对部分已归档仓库的依赖。 | |||
- [[#768](https://github.com/apache/incubator-seata-go/pull/768)] 将解析器更新至 v0.2.17。 | |||
- [[#576](https://github.com/apache/incubator-seata-go/pull/576)] 在 CI 中使用 mirromutth/mysql-action 替换 icomponent/mysql-action。 | |||
- [[#594](https://github.com/apache/incubator-seata-go/pull/594)] 优化分支提交处理器的日志。 | |||
- [[#621](https://github.com/apache/incubator-seata-go/pull/621)] 为 CI 添加 CodeQL。 | |||
- [[#631](https://github.com/apache/incubator-seata-go/pull/631)] 将 crypto 版本从 0.9.0 升级至 0.17.0。 | |||
- [[#652](https://github.com/apache/incubator-seata-go/pull/652)] 将 gRPC 版本从 1.51.0 升级至 1.56.3。 | |||
- [[#667](https://github.com/apache/incubator-seata-go/pull/667)] 将 issue 与 pull request 的邮箱由 dev 更改为 notifications。 | |||
- [[#678](https://github.com/apache/incubator-seata-go/pull/678)] 将模块名重命名为 `seata.apache.org/seata-go`。 | |||
- [[#679](https://github.com/apache/incubator-seata-go/pull/679)] 将 getty 版本从 1.4.9 升级至 1.4.10。 | |||
- [[#714](https://github.com/apache/incubator-seata-go/pull/714)] 优化构建锁键的速度。 | |||
- [[#719](https://github.com/apache/incubator-seata-go/pull/719)] 在 AT 执行 INSERT SQL 时仅保存被插入的字段。 | |||
- [[#721](https://github.com/apache/incubator-seata-go/pull/721)] 修复翻译机器人不可用的问题。 | |||
- [[#758](https://github.com/apache/incubator-seata-go/pull/758)] 移除未使用的文件。 | |||
## 测试(test): | |||
- [[#570](https://github.com/apache/incubator-seata-go/pull/570)] 添加 collection 单元测试。 | |||
- [[#571](https://github.com/apache/incubator-seata-go/pull/571)] 添加 convert 单元测试。 | |||
- [[#572](https://github.com/apache/incubator-seata-go/pull/572)] 添加 reflectx 单元测试。 | |||
- [[#5835f0](https://github.com/apache/incubator-seata-go/commit/5835f09ecfd6edeb04c2961163bc4460f578e942)] 添加 random loadbalance 单元测试。 | |||
- [[#599](https://github.com/apache/incubator-seata-go/pull/599)] 添加 xid loadbalance 单元测试。 | |||
## 文档(doc): | |||
- [[#844](https://github.com/apache/incubator-seata-go/pull/844)] 丰富项目 README。 | |||
- [[#760](https://github.com/apache/incubator-seata-go/pull/760)] V2.0.0 发布更新器。 | |||
- [[#614](https://github.com/apache/incubator-seata-go/pull/614)] 升级具有未知许可证的依赖。 | |||
- [[#632](https://github.com/apache/incubator-seata-go/pull/632)] 添加 ASF 基本配置。 | |||
- [[#633](https://github.com/apache/incubator-seata-go/pull/633)] 优化 ASF 基本配置以移除上下文检查。 | |||
- [[#644](https://github.com/apache/incubator-seata-go/pull/644)] 优化 README 文件。 | |||
- [[#686](https://github.com/apache/incubator-seata-go/pull/686)] 在 CI 中添加更多 linter。 | |||
- [[#737](https://github.com/apache/incubator-seata-go/pull/737)] 修改 README 并更新当前已完成的工作项。 | |||
- [[#756](https://github.com/apache/incubator-seata-go/pull/756)] 更新许可检查器。 | |||
## 贡献者(contributors): | |||
感谢以下贡献者的代码提交。若有遗漏请告知。 | |||
- [luky116](https://github.com/luky116) | |||
- [Code-Fight](https://github.com/Code-Fight) | |||
- [wt-better](https://github.com/wt-better) | |||
- [luweiqianyi](https://github.com/luweiqianyi) | |||
- [wang1309](https://github.com/wang1309) | |||
- [576470954](https://github.com/576470954) | |||
- [No-SilverBullet](https://github.com/No-SilverBullet) | |||
- [solisamicus](https://github.com/solisamicus) | |||
- [marsevilspirit](https://github.com/marsevilspirit) | |||
- [lxfeng1997](https://github.com/lxfeng1997) | |||
- [AlexStocks](https://github.com/AlexStocks) | |||
- [smiletrl](https://github.com/smiletrl) | |||
- [ptyin](https://github.com/ptyin) | |||
- [yizhibian](https://github.com/yizhibian) | |||
- [oldmee](https://github.com/oldmee) | |||
- [air-3](https://github.com/air-3) | |||
- [slievrly](https://github.com/slievrly) | |||
- [xjlgod](https://github.com/xjlgod) | |||
- [baerwang](https://github.com/baerwang) | |||
- [xyombo](https://github.com/xyombo) | |||
- [testwill](https://github.com/testwill) | |||
- [jasondeng1997](https://github.com/jasondeng1997) | |||
- [jsbxyyx](https://github.com/jsbxyyx) | |||
- [iSuperCoder](https://github.com/iSuperCoder) | |||
- [georgehao](https://github.com/georgehao) | |||
- [liuyuecai](https://github.com/liuyuecai) | |||
- [106umao](https://github.com/106umao) | |||
- [FinnTew](https://github.com/FinnTew) | |||
- [funky-eyes](https://github.com/funky-eyes) | |||
- [tanzegen](https://github.com/tanzegen) | |||
- [lovepoem](https://github.com/lovepoem) | |||
- [MinatoWu](https://github.com/MinatoWu) | |||
- [LucienShen-Liu](https://github.com/LucienShen-Liu) | |||
- [panlei-coder](https://github.com/panlei-coder) | |||
- [lixingjia77](https://github.com/lixingjia77) | |||
- [Road2Melon](https://github.com/Road2Melon) | |||
- [Similarityoung](https://github.com/Similarityoung) | |||
- [YvCeung](https://github.com/YvCeung) | |||
- [pjfanning](https://github.com/pjfanning) | |||
- [hokkine](https://github.com/hokkine) | |||
- [zhangymPerson](https://github.com/zhangymPerson) | |||
- [ForestLH](https://github.com/ForestLH) | |||
此外,我们从社区收到了许多有价值的问题、提问与建议,特此致谢。 | |||
</detail> |
@@ -1,48 +0,0 @@ | |||
<!-- | |||
Licensed to the Apache Software Foundation (ASF) under one or more | |||
contributor license agreements. See the NOTICE file distributed with | |||
this work for additional information regarding copyright ownership. | |||
The ASF licenses this file to You under the Apache License, Version 2.0 | |||
(the "License"); you may not use this file except in compliance with | |||
the License. You may obtain a copy of the License at | |||
http://www.apache.org/licenses/LICENSE-2.0 | |||
Unless required by applicable law or agreed to in writing, software | |||
distributed under the License is distributed on an "AS IS" BASIS, | |||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
See the License for the specific language governing permissions and | |||
limitations under the License. | |||
--> | |||
### Development notes | |||
### dev version | |||
Seata-go is an easy-to-use, high-performance, open source distributed transaction solution. | |||
The version is updated as follows: | |||
### feature: | |||
- [[#123](https://github.com/apache/incubator-seata-go/pull/123)] add two phase and dubbo | |||
### bugfix: | |||
- [[#130](https://github.com/apache/incubator-seata-go/pull/130)] getty session auto close bug | |||
### optimize: | |||
- [[#125](https://github.com/apache/incubator-seata-go/pull/125)] optimize named for the resource manager api and tcc resource | |||
### test: | |||
- [[#xxx](https://github.com/apache/incubator-seata-go/pull/xxx)] test case for xxx | |||
### contributors: | |||
Thanks to these contributors for their code commits. Please report an unintended omission. | |||
- [slievrly](https://github.com/slievrly) | |||
Also, we receive many valuable issues, questions and advices from our community. Thanks for you all. |
@@ -1,50 +0,0 @@ | |||
<!-- | |||
Licensed to the Apache Software Foundation (ASF) under one or more | |||
contributor license agreements. See the NOTICE file distributed with | |||
this work for additional information regarding copyright ownership. | |||
The ASF licenses this file to You under the Apache License, Version 2.0 | |||
(the "License"); you may not use this file except in compliance with | |||
the License. You may obtain a copy of the License at | |||
http://www.apache.org/licenses/LICENSE-2.0 | |||
Unless required by applicable law or agreed to in writing, software | |||
distributed under the License is distributed on an "AS IS" BASIS, | |||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
See the License for the specific language governing permissions and | |||
limitations under the License. | |||
--> | |||
### 开发记录 | |||
### dev version | |||
Seata-go 是一款开源的分布式事务解决方案,提供高性能和简单易用的分布式事务服务。 | |||
此版本更新如下: | |||
### feature: | |||
- [[#123](https://github.com/apache/incubator-seata-go/pull/123)] 添加二阶段事务接口,以及dubbo集成 | |||
### bugfix: | |||
- [[#130](https://github.com/apache/incubator-seata-go/pull/130)] 修复getty session自动关闭的bug | |||
### optimize: | |||
- [[#125](https://github.com/apache/incubator-seata-go/pull/125)] 优化resourceManagerApi和tccResource功能 | |||
### test: | |||
- [[#xxx](https://github.com/apache/incubator-seata-go/pull/xxx)] 添加xxx的单元测试 | |||
### contributors: | |||
非常感谢以下 contributors 的代码贡献。若有无意遗漏,请报告。 | |||
- [slievrly](https://github.com/slievrly) | |||
同时,我们收到了社区反馈的很多有价值的issue和建议,非常感谢大家。 |
@@ -0,0 +1,50 @@ | |||
server: | |||
port: 8091 | |||
maxRollbackRetryTimeout: -1 | |||
maxCommitRetryTimeout: -1 | |||
rollbackRetryTimeoutUnlockEnable: true | |||
asyncCommittingRetryPeriod: 1s | |||
committingRetryPeriod: 5s | |||
rollingBackRetryPeriod: 1s | |||
timeoutRetryPeriod: 1s | |||
streamMessageTimeout: 30s | |||
rollbackDeadSeconds: 12 | |||
enforcementPolicy: | |||
minTime: 5s | |||
permitWithoutStream: true | |||
serverParameters: | |||
maxConnectionIdle: 15s | |||
maxConnectionAge: 30s | |||
maxConnectionAgeGrace: 5s | |||
time: 5s | |||
timeout: 1s | |||
serverTLS: | |||
enable: false | |||
certFilePath: "" | |||
keyFilePath: "" | |||
clientParameters: | |||
time: 10s | |||
timeout: 1s | |||
permitWithoutStream: true | |||
storage: | |||
# inMemory driver only for testing | |||
# inmemory: | |||
mysql: | |||
dsn: "root:123456@tcp(127.0.0.1:3306)/seata?timeout=1s&readTimeout=1s&writeTimeout=1s&parseTime=true&loc=Local&charset=utf8mb4,utf8" | |||
globaltable: global_table | |||
branchtable: branch_table | |||
locktable: lock_table | |||
maxopenconnections: 100 | |||
maxidleconnections: 20 | |||
maxlifetime: 4h | |||
# pgsql: | |||
# dsn: "postgres://postgres:123456@127.0.0.1:5432/seata?search_path=public&sslmode=disable" | |||
# globaltable: global_table | |||
# branchtable: branch_table | |||
# locktable: lock_table | |||
# maxopenconnections: 100 | |||
# maxidleconnections: 20 | |||
# maxlifetime: 4h | |||
log: | |||
logPath: /Users/scottlewis/dksl/git/1/seata-golang/cmd/profiles/dev/seata.log | |||
logLevel: info |
@@ -1,22 +0,0 @@ | |||
/* | |||
* Licensed to the Apache Software Foundation (ASF) under one or more | |||
* contributor license agreements. See the NOTICE file distributed with | |||
* this work for additional information regarding copyright ownership. | |||
* The ASF licenses this file to You under the Apache License, Version 2.0 | |||
* (the "License"); you may not use this file except in compliance with | |||
* the License. You may obtain a copy of the License at | |||
* | |||
* http://www.apache.org/licenses/LICENSE-2.0 | |||
* | |||
* Unless required by applicable law or agreed to in writing, software | |||
* distributed under the License is distributed on an "AS IS" BASIS, | |||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
* See the License for the specific language governing permissions and | |||
* limitations under the License. | |||
*/ | |||
package main | |||
func main() { | |||
// start the server | |||
} |
@@ -0,0 +1,138 @@ | |||
package main | |||
import ( | |||
"fmt" | |||
"net" | |||
"net/http" | |||
_ "net/http/pprof" | |||
"os" | |||
"github.com/urfave/cli/v2" | |||
"google.golang.org/grpc" | |||
"github.com/opentrx/seata-golang/v2/pkg/apis" | |||
"github.com/opentrx/seata-golang/v2/pkg/tc/config" | |||
_ "github.com/opentrx/seata-golang/v2/pkg/tc/metrics" | |||
"github.com/opentrx/seata-golang/v2/pkg/tc/server" | |||
_ "github.com/opentrx/seata-golang/v2/pkg/tc/storage/driver/inmemory" | |||
_ "github.com/opentrx/seata-golang/v2/pkg/tc/storage/driver/mysql" | |||
_ "github.com/opentrx/seata-golang/v2/pkg/tc/storage/driver/pgsql" | |||
"github.com/opentrx/seata-golang/v2/pkg/util/log" | |||
"github.com/opentrx/seata-golang/v2/pkg/util/uuid" | |||
) | |||
func main() { | |||
app := &cli.App{ | |||
Commands: []*cli.Command{ | |||
{ | |||
Name: "start", | |||
Usage: "start seata golang tc server", | |||
Flags: []cli.Flag{ | |||
&cli.StringFlag{ | |||
Name: "config", | |||
Aliases: []string{"c"}, | |||
Usage: "Load configuration from `FILE`", | |||
}, | |||
&cli.StringFlag{ | |||
Name: "serverNode", | |||
Aliases: []string{"n"}, | |||
Value: "1", | |||
Usage: "server node id, such as 1, 2, 3. default is 1", | |||
}, | |||
}, | |||
Action: func(c *cli.Context) error { | |||
configPath := c.String("config") | |||
serverNode := c.Int64("serverNode") | |||
cfg, err := resolveConfiguration(configPath) | |||
if err != nil || cfg == nil { | |||
return err | |||
} | |||
_ = uuid.Init(serverNode) | |||
log.Init(cfg.Log.LogPath, cfg.Log.LogLevel) | |||
address := fmt.Sprintf(":%v", cfg.Server.Port) | |||
lis, err := net.Listen("tcp", address) | |||
if err != nil { | |||
log.Fatalf("failed to listen: %v", err) | |||
} | |||
s := grpc.NewServer(grpc.KeepaliveEnforcementPolicy(cfg.GetEnforcementPolicy()), | |||
grpc.KeepaliveParams(cfg.GetServerParameters()), grpc.Creds(cfg.GetServerTLS())) | |||
tc := server.NewTransactionCoordinator(cfg) | |||
apis.RegisterTransactionManagerServiceServer(s, tc) | |||
apis.RegisterResourceManagerServiceServer(s, tc) | |||
go func() { | |||
http.HandleFunc("/health", func(writer http.ResponseWriter, request *http.Request) { | |||
writer.WriteHeader(http.StatusOK) | |||
}) | |||
err = http.ListenAndServe(":10001", nil) | |||
if err != nil { | |||
return | |||
} | |||
}() | |||
printStartUpLogo() | |||
log.Infof("start to serve on port %d", cfg.Server.Port) | |||
if err := s.Serve(lis); err != nil { | |||
log.Fatalf("failed to serve: %v", err) | |||
} | |||
return nil | |||
}, | |||
}, | |||
}, | |||
} | |||
err := app.Run(os.Args) | |||
if err != nil { | |||
log.Error(err) | |||
} | |||
} | |||
func resolveConfiguration(configPath string) (*config.Configuration, error) { | |||
var configurationPath string | |||
if configPath != "" { | |||
configurationPath = configPath | |||
} else if os.Getenv("SEATA_CONFIGURATION_PATH") != "" { | |||
configurationPath = os.Getenv("SEATA_CONFIGURATION_PATH") | |||
} | |||
if configurationPath == "" { | |||
return nil, fmt.Errorf("configuration path unspecified") | |||
} | |||
fp, err := os.Open(configurationPath) | |||
if err != nil { | |||
return nil, err | |||
} | |||
defer func(fp *os.File) { | |||
err = fp.Close() | |||
if err != nil { | |||
log.Error(err) | |||
} | |||
}(fp) | |||
cfg, err := config.Parse(fp) | |||
if err != nil { | |||
return nil, fmt.Errorf("error parsing %s: %v", configurationPath, err) | |||
} | |||
return cfg, nil | |||
} | |||
func printStartUpLogo() { | |||
logoStr := " _ _ \n" + | |||
" ___ ___ __ _| |_ __ _ __ _ ___ | | __ _ _ __ __ _ \n" + | |||
"/ __|/ _ \\/ _` | __/ _` |_____ / _` |/ _ \\| |/ _` | '_ \\ / _` |\n" + | |||
"\\__ \\ __/ (_| | || (_| |_____| (_| | (_) | | (_| | | | | (_| |\n" + | |||
"|___/\\___|\\__,_|\\__\\__,_| \\__, |\\___/|_|\\__,_|_| |_|\\__, |\n" + | |||
" |___/ |___/ " | |||
fmt.Println(logoStr) | |||
fmt.Println("Seata-Golang (v2) Transaction Coordinator (TC)") | |||
fmt.Println() | |||
} |
@@ -0,0 +1,17 @@ | |||
FROM alpine:3.14.1 | |||
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.ustc.edu.cn/g' /etc/apk/repositories && \ | |||
apk add --no-cache tcpdump lsof net-tools tzdata curl dumb-init libc6-compat | |||
ENV TZ Asia/Shanghai | |||
ENV PATH=$PATH:/opt/seata-golang/bin | |||
WORKDIR /opt/seata-golang/bin | |||
COPY tc /opt/seata-golang/bin/tc | |||
COPY config.yml /etc/seata-golang/config.yml | |||
RUN chmod +x /opt/seata-golang/bin/tc | |||
ENTRYPOINT ["/usr/bin/dumb-init", "--"] | |||
CMD ["/opt/seata-golang/bin/tc", "start", "-config", "/etc/seata-golang/config.yml"] |
@@ -0,0 +1,44 @@ | |||
server: | |||
port: 8091 | |||
maxRollbackRetryTimeout: -1 | |||
maxCommitRetryTimeout: -1 | |||
rollbackRetryTimeoutUnlockEnable: true | |||
asyncCommittingRetryPeriod: 10s | |||
committingRetryPeriod: 1s | |||
rollingBackRetryPeriod: 1s | |||
timeoutRetryPeriod: 1s | |||
enforcementPolicy: | |||
minTime: 5s | |||
permitWithoutStream: true | |||
serverParameters: | |||
maxConnectionIdle: 15s | |||
maxConnectionAge: 30s | |||
maxConnectionAgeGrace: 5s | |||
time: 5s | |||
timeout: 1s | |||
clientParameters: | |||
time: 10s | |||
timeout: 1s | |||
permitWithoutStream: true | |||
storage: | |||
# inMemory driver only for testing | |||
inmemory: | |||
# mysql: | |||
# dsn: "root:123456@tcp(127.0.0.1:3306)/seata?timeout=1s&readTimeout=1s&writeTimeout=1s&parseTime=true&loc=Local&charset=utf8mb4,utf8" | |||
# globaltable: global_table2 | |||
# branchtable: branch_table2 | |||
# locktable: lock_table | |||
# maxopenconnections: 100 | |||
# maxidleconnections: 20 | |||
# maxlifetime: 4h | |||
# pgsql: | |||
# dsn: "postgres://postgres:123456@127.0.0.1:5432/seata?search_path=public&sslmode=disable" | |||
# globaltable: global_table | |||
# branchtable: branch_table | |||
# locktable: lock_table | |||
# maxopenconnections: 100 | |||
# maxidleconnections: 20 | |||
# maxlifetime: 4h | |||
log: | |||
logPath: seata.log | |||
logLevel: info |
@@ -0,0 +1,74 @@ | |||
# seata-golang | |||
[](https://github.com/opentrx/seata-golang/blob/v2/LICENSE) | |||
## 简介 | [English](https://github.com/opentrx/seata-golang/blob/v2/README.md) | |||
seata-golang是一个用于解决分布式事务的中间件,是基于Go语言版本的seata。 | |||
### seata-golang与[seata](https://github.com/seata/seata) 的区别 | |||
| 特性 | seata | seata-golang | 备注 | | |||
| ---- | :----: | :----: | --- | | |||
| AT mode | √ | √ | | | |||
| TCC mode | √ | √ | | | |||
| SAGA mode | √ | × | | | |||
| rpc | √ | √ | [dev branch](https://github.com/opentrx/seata-golang/tree/dev) | | |||
| grpc | × | √ | [v2 branch](https://github.com/opentrx/seata-golang/tree/v2) | | |||
## 架构 | |||
<img alt="seata-flow" width="500px" src="https://github.com/opentrx/seata-golang/blob/v2/docs/images/seata-flow.png" /> | |||
一个典型的seata分布式事务的生命周期: | |||
- TM向TC发起全局分布式事务, TC为全局事务分配一个唯一事务id:XID。 | |||
- XID在微服务调用链中传播。 | |||
- RM向TC注册本地事务为全局事务的一个分支。 | |||
- TM向TC发起全局事务提交或全局事务回滚。 | |||
- TC向所有参与全局事务的分支事务发起本地提交或本地回滚。 | |||
## 目录结构 | |||
- cmd: 启动TC server的入口 | |||
- profiles/dev/config.yml: TC 配置文件 | |||
- tc/main.go: TC 启动文件 | |||
- dist: docker环境 | |||
- docs: 相关文档 | |||
- pkg: TC + RM + TM 核心模块实现 | |||
- server/db/*.sql: 用于启动TC所必须的创建数据库表的SQL | |||
## 启动方法 | |||
- ### TC server | |||
```bash | |||
cd ${projectpath}/cmd/tc | |||
go build -o tc_server | |||
# 为TC server创建数据库 `seata` | |||
# 修改配置文件 ${projectpath}/cmd/profiles/dev/config.yml 的配置项 storage.dsn.mysql | |||
./tc_server start -config ${projectpath}/cmd/profiles/dev/config.yml | |||
``` | |||
- ### Client | |||
请查看demo演示[seata-go-samples](https://github.com/opentrx/seata-go-samples) | |||
- ### 前提条件 | |||
- MySQL服务器 | |||
- Golang 版本 >= 1.15 | |||
- 带主键的业务数据表 | |||
## 设计与实现 | |||
seata-golang的AT模式和TCC模式的设计与[seata](https://github.com/seata/seata) 是一致的。 | |||
请参考[什么是seata](https://seata.io/en-us/docs/overview/what-is-seata.html) | |||
## 相关参考 | |||
- [什么是seata AT模式?](https://seata.io/en-us/docs/dev/mode/at-mode.html) | |||
- [什么是seata TCC模式?](https://seata.io/en-us/docs/dev/mode/tcc-mode.html) | |||
- [grpc](https://grpc.io/) | |||
- [dubbogo](https://github.com/dubbogo) | |||
- [mysql-driver](https://github.com/opentrx/mysql) | |||
- [seata-go-samples](https://github.com/opentrx/seata-go-samples) | |||
## 联系方式 | |||
如果对seata-golang有问题,可以通过钉钉联系我们。钉钉群号是 33069364。 | |||
<img alt="DingTalk Group" src="https://github.com/opentrx/seata-golang/blob/dev/docs/pics/33069364.png" width="200px" /> | |||
## 贡献 | |||
欢迎来为seata-golang提交issue和pull-request! | |||
要给seata-golang提交代码, 可以fork opentrx/seata-golang,然后提交代码到你fork的仓库分支上,最后提交pull request。 | |||
## 开源协议 | |||
seata-golang遵循Apache 2.0开源协议。 查看 [LICENSE](https://github.com/opentrx/seata-golang/blob/v2/LICENSE) |
@@ -1,115 +1,25 @@ | |||
module seata.apache.org/seata-go | |||
module github.com/opentrx/seata-golang/v2 | |||
go 1.20 | |||
go 1.15 | |||
require ( | |||
dubbo.apache.org/dubbo-go/v3 v3.0.4 | |||
github.com/DATA-DOG/go-sqlmock v1.5.0 | |||
github.com/apache/dubbo-getty v1.5.0 | |||
github.com/arana-db/parser v0.2.17 | |||
github.com/bluele/gcache v0.0.2 | |||
github.com/dsnet/compress v0.0.1 | |||
github.com/dubbogo/gost v1.13.2 | |||
github.com/gin-gonic/gin v1.9.1 | |||
github.com/go-sql-driver/mysql v1.6.0 | |||
github.com/goccy/go-json v0.10.2 | |||
github.com/golang/mock v1.6.0 | |||
github.com/google/uuid v1.3.0 | |||
github.com/dubbogo/gost v1.11.11 | |||
github.com/go-sql-driver/mysql v1.5.0 | |||
github.com/go-xorm/xorm v0.7.9 | |||
github.com/gogo/protobuf v1.3.2 | |||
github.com/lib/pq v1.0.0 | |||
github.com/natefinch/lumberjack v2.0.0+incompatible | |||
github.com/pierrec/lz4/v4 v4.1.17 | |||
github.com/pkg/errors v0.9.1 | |||
github.com/prometheus/client_golang v1.12.2 | |||
github.com/prometheus/common v0.32.1 | |||
github.com/sijms/go-ora/v2 v2.5.17 | |||
github.com/stretchr/testify v1.8.3 | |||
go.uber.org/atomic v1.9.0 | |||
go.uber.org/zap v1.27.0 | |||
google.golang.org/grpc v1.56.3 | |||
gopkg.in/yaml.v2 v2.4.0 | |||
vimagination.zapto.org/byteio v0.0.0-20200222190125-d27cba0f0b10 | |||
) | |||
require ( | |||
github.com/agiledragon/gomonkey/v2 v2.12.0 | |||
github.com/golang/protobuf v1.5.3 | |||
go.etcd.io/etcd/api/v3 v3.5.6 | |||
go.etcd.io/etcd/client/v3 v3.5.6 | |||
google.golang.org/protobuf v1.30.0 | |||
) | |||
require github.com/knadh/koanf v1.5.0 | |||
require ( | |||
github.com/RoaringBitmap/roaring v1.2.0 // indirect | |||
github.com/Workiva/go-datastructures v1.0.52 // indirect | |||
github.com/apache/dubbo-go-hessian2 v1.11.4 // indirect | |||
github.com/beorn7/perks v1.0.1 // indirect | |||
github.com/bits-and-blooms/bitset v1.2.0 // indirect | |||
github.com/bytedance/sonic v1.9.1 // indirect | |||
github.com/cespare/xxhash/v2 v2.2.0 // indirect | |||
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect | |||
github.com/coreos/go-semver v0.3.0 // indirect | |||
github.com/coreos/go-systemd/v22 v22.3.2 // indirect | |||
github.com/creasty/defaults v1.5.2 // indirect | |||
github.com/davecgh/go-spew v1.1.1 // indirect | |||
github.com/gabriel-vasile/mimetype v1.4.2 // indirect | |||
github.com/gin-contrib/sse v0.1.0 // indirect | |||
github.com/go-ole/go-ole v1.2.6 // indirect | |||
github.com/go-playground/locales v0.14.1 // indirect | |||
github.com/go-playground/universal-translator v0.18.1 // indirect | |||
github.com/gogo/protobuf v1.3.2 // indirect | |||
github.com/golang/snappy v0.0.4 // indirect | |||
github.com/gorilla/websocket v1.4.2 // indirect | |||
github.com/jinzhu/copier v0.3.5 // indirect | |||
github.com/json-iterator/go v1.1.12 // indirect | |||
github.com/k0kubun/pp v3.0.1+incompatible // indirect | |||
github.com/klauspost/cpuid/v2 v2.2.4 // indirect | |||
github.com/leodido/go-urn v1.2.4 // indirect | |||
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect | |||
github.com/magiconair/properties v1.8.6 // indirect | |||
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect | |||
github.com/mitchellh/copystructure v1.2.0 // indirect | |||
github.com/mitchellh/mapstructure v1.5.0 // indirect | |||
github.com/mitchellh/reflectwalk v1.0.2 // indirect | |||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect | |||
github.com/modern-go/reflect2 v1.0.2 // indirect | |||
github.com/mschoch/smat v0.2.0 // indirect | |||
github.com/pelletier/go-toml/v2 v2.0.8 // indirect | |||
github.com/pingcap/errors v0.11.5-0.20210425183316-da1aaba5fb63 // indirect | |||
github.com/pmezard/go-difflib v1.0.0 // indirect | |||
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect | |||
github.com/prometheus/client_model v0.2.0 // indirect | |||
github.com/prometheus/procfs v0.7.3 // indirect | |||
github.com/satori/go.uuid v1.2.1-0.20181028125025-b2ce2384e17b // indirect | |||
github.com/shirou/gopsutil/v3 v3.22.2 // indirect | |||
github.com/tklauser/go-sysconf v0.3.10 // indirect | |||
github.com/tklauser/numcpus v0.4.0 // indirect | |||
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect | |||
github.com/ugorji/go/codec v1.2.11 // indirect | |||
github.com/yusufpapurcu/wmi v1.2.2 // indirect | |||
go.etcd.io/etcd/client/pkg/v3 v3.5.6 // indirect | |||
go.uber.org/multierr v1.10.0 // indirect | |||
golang.org/x/arch v0.3.0 // indirect | |||
golang.org/x/text v0.14.0 // indirect | |||
github.com/prometheus/client_golang v1.9.0 | |||
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a | |||
github.com/stretchr/testify v1.7.0 // indirect | |||
github.com/urfave/cli/v2 v2.3.0 | |||
go.uber.org/atomic v1.7.0 | |||
go.uber.org/zap v1.17.0 | |||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 // indirect | |||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007 // indirect | |||
google.golang.org/grpc v1.38.0 | |||
gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect | |||
gopkg.in/yaml.v3 v3.0.1 // indirect | |||
) | |||
require ( | |||
github.com/BurntSushi/toml v1.1.0 // indirect | |||
github.com/go-playground/validator/v10 v10.14.0 // indirect | |||
github.com/klauspost/compress v1.15.11 | |||
github.com/mattn/go-colorable v0.1.8 // indirect | |||
github.com/mattn/go-isatty v0.0.19 // indirect | |||
github.com/pelletier/go-toml v1.9.3 // indirect | |||
github.com/pingcap/log v0.0.0-20210906054005-afc726e70354 // indirect | |||
golang.org/x/crypto v0.21.0 // indirect | |||
golang.org/x/net v0.23.0 // indirect | |||
golang.org/x/sys v0.18.0 // indirect | |||
google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect | |||
vimagination.zapto.org/memio v0.0.0-20200222190306-588ebc67b97d // indirect | |||
gopkg.in/yaml.v2 v2.4.0 | |||
xorm.io/builder v0.3.9 | |||
) | |||
replace github.com/dubbogo/gost => github.com/dubbogo/gost v1.13.2 | |||
exclude github.com/polarismesh/polaris-go v1.3.0-alpha |
@@ -1,29 +0,0 @@ | |||
# | |||
# Licensed to the Apache Software Foundation (ASF) under one or more | |||
# contributor license agreements. See the NOTICE file distributed with | |||
# this work for additional information regarding copyright ownership. | |||
# The ASF licenses this file to You under the Apache License, Version 2.0 | |||
# (the "License"); you may not use this file except in compliance with | |||
# the License. You may obtain a copy of the License at | |||
# | |||
# http://www.apache.org/licenses/LICENSE-2.0 | |||
# | |||
# Unless required by applicable law or agreed to in writing, software | |||
# distributed under the License is distributed on an "AS IS" BASIS, | |||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
# See the License for the specific language governing permissions and | |||
# limitations under the License. | |||
# | |||
# format go imports style | |||
go install golang.org/x/tools/cmd/goimports | |||
goimports -local seata.apache.org/seata-go -w . | |||
# format licence style | |||
go install github.com/apache/skywalking-eyes/cmd/license-eye@latest | |||
license-eye header fix | |||
# check dependency licence is valid | |||
license-eye dependency check | |||
# format go.mod | |||
go mod tidy |
@@ -1,48 +0,0 @@ | |||
# | |||
# Licensed to the Apache Software Foundation (ASF) under one or more | |||
# contributor license agreements. See the NOTICE file distributed with | |||
# this work for additional information regarding copyright ownership. | |||
# The ASF licenses this file to You under the Apache License, Version 2.0 | |||
# (the "License"); you may not use this file except in compliance with | |||
# the License. You may obtain a copy of the License at | |||
# | |||
# http://www.apache.org/licenses/LICENSE-2.0 | |||
# | |||
# Unless required by applicable law or agreed to in writing, software | |||
# distributed under the License is distributed on an "AS IS" BASIS, | |||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
# See the License for the specific language governing permissions and | |||
# limitations under the License. | |||
#!/bin/bash | |||
set -e | |||
set -x | |||
echo 'start integrate-test' | |||
# set root workspace | |||
ROOT_DIR=$(pwd) | |||
echo "integrate-test root work-space -> ${ROOT_DIR}" | |||
# show all github-env | |||
echo "github current commit id -> $2" | |||
echo "github pull request branch -> ${GITHUB_REF}" | |||
echo "github pull request slug -> ${GITHUB_REPOSITORY}" | |||
echo "github pull request repo slug -> ${GITHUB_REPOSITORY}" | |||
echo "github pull request actor -> ${GITHUB_ACTOR}" | |||
echo "github pull request repo param -> $1" | |||
echo "github pull request base branch -> $3" | |||
echo "github pull request head branch -> ${GITHUB_HEAD_REF}" | |||
echo "use seata-go-samples $3 branch for integration testing" | |||
git clone https://github.com/apache/incubator-seata-go-samples samples && cd samples | |||
# update seata-go to current commit id | |||
go mod edit -replace=seata.apache.org/seata-go=github.com/"$1"@"$2" | |||
go mod tidy | |||
# start integrate test | |||
./start_integrate_test.sh |
@@ -1,9 +0,0 @@ | |||
{{.LicenseContent }} | |||
{{ range .Groups }} | |||
======================================================================== | |||
{{.LicenseID}} licenses | |||
======================================================================== | |||
{{range .Deps}} | |||
{{.Name}} {{.Version}} {{.LicenseID}} | |||
{{- end }} | |||
{{ end }} |
@@ -1,80 +0,0 @@ | |||
# | |||
# Licensed to the Apache Software Foundation (ASF) under one or more | |||
# contributor license agreements. See the NOTICE file distributed with | |||
# this work for additional information regarding copyright ownership. | |||
# The ASF licenses this file to You under the Apache License, Version 2.0 | |||
# (the "License"); you may not use this file except in compliance with | |||
# the License. You may obtain a copy of the License at | |||
# | |||
# http://www.apache.org/licenses/LICENSE-2.0 | |||
# | |||
# Unless required by applicable law or agreed to in writing, software | |||
# distributed under the License is distributed on an "AS IS" BASIS, | |||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
# See the License for the specific language governing permissions and | |||
# limitations under the License. | |||
# | |||
VERSION=$(shell cat "./VERSION" 2> /dev/null) | |||
GO_FLAGS := -ldflags "-X main.Branch=$(GIT_BRANCH) -X main.Revision=$(GIT_REVISION) -X main.Version=$(VERSION) -extldflags \"-static\" -s -w" -tags netgo | |||
GO = go | |||
GO_PATH = $(shell $(GO) env GOPATH) | |||
GO_OS = $(shell $(GO) env GOOS) | |||
ifeq ($(GO_OS), darwin) | |||
GO_OS = mac | |||
endif | |||
ifeq ($(shell uname -s), Darwin) | |||
SHA256_CMD = shasum -a 256 | |||
else | |||
SHA256_CMD = sha256sum | |||
endif | |||
# License environment | |||
GO_LICENSE_CHECKER_DIR = license-header-checker-$(GO_OS) | |||
GO_LICENSE_CHECKER = $(GO_PATH)/bin/license-header-checker | |||
LICENSE_DIR = /tmp/tools/license | |||
# format import code | |||
format-import: | |||
go get -d github.com/dubbogo/tools/cmd/imports-formatter | |||
imports-formatter -path . -module seata.apache.org/seata-go -bl false | |||
unit-test: | |||
go test ./pkg/... -coverprofile=coverage.txt -covermode=atomic | |||
# Generate binaries for a Cortex release | |||
dist dist/seatago-linux-amd64 dist/seatago-darwin-amd64 dist/seatago-linux-amd64-sha-256 dist/seatago-darwin-amd64-sha-256: | |||
rm -fr ./dist | |||
mkdir -p ./dist | |||
GOOS="linux" GOARCH="amd64" CGO_ENABLED=0 go build $(GO_FLAGS) -o ./dist/seatago-linux-amd64 ./cmd | |||
GOOS="darwin" GOARCH="amd64" CGO_ENABLED=0 go build $(GO_FLAGS) -o ./dist/seatago-darwin-amd64 ./cmd | |||
$(SHA256_CMD) ./dist/seatago-darwin-amd64 | cut -d ' ' -f 1 > ./dist/seatago-darwin-amd64-sha-256 | |||
$(SHA256_CMD) ./dist/seatago-linux-amd64 | cut -d ' ' -f 1 > ./dist/seatago-linux-amd64-sha-256 | |||
# Generate binaries for a Cortex release | |||
build dist/seatago dist/seatago-sha-256: | |||
rm -fr ./dist | |||
mkdir -p ./dist | |||
CGO_ENABLED=0 go build $(GO_FLAGS) -o ./dist/seatago ./cmd | |||
$(SHA256_CMD) ./dist/seatago | cut -d ' ' -f 1 > ./dist/seatago-sha-256 | |||
#docker-build: | |||
# docker build -t seatago/seatago:latest . | |||
integration-test: | |||
@go clean -testcache | |||
go test -tags integration -v ./test/... | |||
clean: | |||
@rm -rf coverage.txt | |||
@rm -rf dist | |||
prepareLic: | |||
echo 'The makefile is for ci test and has dependencies. Do not run it locally. If you want to run the unit tests, run command `go test ./...` directly.' | |||
$(GO_LICENSE_CHECKER) -version || (wget https://github.com/lsm-dev/license-header-checker/releases/download/v1.2.0/$(GO_LICENSE_CHECKER_DIR).zip -O $(GO_LICENSE_CHECKER_DIR).zip && unzip -o $(GO_LICENSE_CHECKER_DIR).zip && mkdir -p $(GO_PATH)/bin/ && cp $(GO_LICENSE_CHECKER_DIR)/64bit/license-header-checker $(GO_PATH)/bin/) | |||
ls /tmp/tools/license/license.txt || wget -P $(LICENSE_DIR) https://github.com/dubbogo/resources/raw/master/tools/license/license.txt | |||
.PHONY: license | |||
license: prepareLic | |||
$(GO_LICENSE_CHECKER) -v -a -r -i vendor $(LICENSE_DIR)/license.txt . go && [[ -z `git status -s` ]] |
@@ -0,0 +1,413 @@ | |||
syntax = "proto3"; | |||
package apis; | |||
import "github.com/gogo/protobuf/gogoproto/gogo.proto"; | |||
import "google/protobuf/any.proto"; | |||
option go_package="github.com/opentrx/seata-golang/v2/pkg/apis"; | |||
enum ResultCode { | |||
ResultCodeFailed = 0; | |||
ResultCodeSuccess = 1; | |||
} | |||
enum ExceptionCode { | |||
// Unknown transaction error code. | |||
UnknownErr = 0; | |||
// BeginFailed | |||
BeginFailed = 1; | |||
// Lock key conflict transaction error code. | |||
LockKeyConflict = 2; | |||
// Io transaction error code. | |||
IO = 3; | |||
// Branch rollback failed retryable transaction error code. | |||
BranchRollbackFailedRetryable = 4; | |||
// Branch rollback failed unretryable transaction error code. | |||
BranchRollbackFailedUnretryable = 5; | |||
// Branch register failed transaction error code. | |||
BranchRegisterFailed = 6; | |||
// Branch report failed transaction error code. | |||
BranchReportFailed = 7; | |||
// Lockable check failed transaction error code. | |||
LockableCheckFailed = 8; | |||
// Branch transaction not exist transaction error code. | |||
BranchTransactionNotExist = 9; | |||
// Global transaction not exist transaction error code. | |||
GlobalTransactionNotExist = 10; | |||
// Global transaction not active transaction error code. | |||
GlobalTransactionNotActive = 11; | |||
// Global transaction status invalid transaction error code. | |||
GlobalTransactionStatusInvalid = 12; | |||
// Failed to send branch commit request transaction error code. | |||
FailedToSendBranchCommitRequest = 13; | |||
// Failed to send branch rollback request transaction error code. | |||
FailedToSendBranchRollbackRequest = 14; | |||
// Failed to add branch transaction error code. | |||
FailedToAddBranch = 15; | |||
// Failed to lock global transaction error code. | |||
FailedLockGlobalTransaction = 16; | |||
// FailedWriteSession | |||
FailedWriteSession = 17; | |||
// Failed to holder error code | |||
FailedStore = 18; | |||
} | |||
enum BranchMessageType { | |||
TypeBranchCommit = 0; | |||
TypeBranchCommitResult = 1; | |||
TypeBranchRollback = 2; | |||
TypeBranchRollBackResult = 3; | |||
} | |||
message GlobalSession { | |||
enum GlobalStatus { | |||
// Un known global status. | |||
UnknownGlobalStatus = 0; | |||
// PHASE 1: can accept new branch registering. | |||
Begin = 1; | |||
// PHASE 2: Running Status: may be changed any time. | |||
Committing = 2; | |||
// The Commit retrying. | |||
// Retrying commit after a recoverable failure. | |||
CommitRetrying = 3; | |||
// Rolling back global status. | |||
RollingBack = 4; | |||
// The Rollback retrying. | |||
// Retrying rollback after a recoverable failure. | |||
RollbackRetrying = 5; | |||
// The Timeout rolling back. | |||
// Rolling back since timeout | |||
TimeoutRollingBack = 6; | |||
// The Timeout rollback retrying. | |||
// Retrying rollback (since timeout) after a recoverable failure. | |||
TimeoutRollbackRetrying = 7; | |||
// All branches can be async committed. The committing is NOT done yet, but it can be seen as | |||
// committed for TM/RM rpc_client. | |||
AsyncCommitting = 8; | |||
// PHASE 2: Final Status: will NOT change any more. | |||
// Finally: global transaction is successfully committed. | |||
Committed = 9; | |||
// The Commit failed. | |||
// Finally: failed to commit | |||
CommitFailed = 10; | |||
// The RolledBack. | |||
// Finally: global transaction is successfully rollback. | |||
RolledBack = 11; | |||
// The Rollback failed. | |||
// Finally: failed to rollback | |||
RollbackFailed = 12; | |||
// The Timeout rolled back. | |||
// Finally: global transaction is successfully rollback since timeout. | |||
TimeoutRolledBack = 13; | |||
// The Timeout rollback failed. | |||
// Finally: failed to rollback since timeout | |||
TimeoutRollbackFailed = 14; | |||
// The Finished. | |||
// Not managed in getty_session MAP any more | |||
Finished = 15; | |||
} | |||
string Addressing = 1 [(gogoproto.moretags) = "xorm:\"addressing\""]; | |||
string XID = 2 [(gogoproto.moretags) = "xorm:\"xid\""]; | |||
int64 TransactionID = 3 [(gogoproto.moretags) = "xorm:\"transaction_id\""]; | |||
string TransactionName = 4 [(gogoproto.moretags) = "xorm:\"transaction_name\""]; | |||
int32 Timeout = 5 [(gogoproto.moretags) = "xorm:\"timeout\""]; | |||
int64 BeginTime = 6 [(gogoproto.moretags) = "xorm:\"begin_time\""]; | |||
GlobalStatus Status = 7 [(gogoproto.moretags) = "xorm:\"status\""]; | |||
bool Active = 8 [(gogoproto.moretags) = "xorm:\"active\""]; | |||
} | |||
message BranchSession { | |||
enum BranchType { | |||
AT = 0; | |||
TCC = 1; | |||
SAGA = 2; | |||
XA = 3; | |||
} | |||
enum BranchStatus { | |||
// description:BranchStatus_Unknown branch status. | |||
UnknownBranchStatus = 0; | |||
// description:BranchStatus_Registered to TC. | |||
Registered = 1; | |||
// The Phase one done. | |||
// description:Branch logic is successfully done at phase one. | |||
PhaseOneDone = 2; | |||
// The Phase one failed. | |||
// description:Branch logic is failed at phase one. | |||
PhaseOneFailed = 3; | |||
// The Phase one timeout. | |||
// description:Branch logic is NOT reported for a timeout. | |||
PhaseOneTimeout = 4; | |||
// The Phase two committed. | |||
// description:Commit logic is successfully done at phase two. | |||
PhaseTwoCommitted = 5; | |||
// The Phase two commit failed retryable. | |||
// description:Commit logic is failed but retryable. | |||
PhaseTwoCommitFailedRetryable = 6; | |||
// The Phase two commit failed and can not retry. | |||
// description:Commit logic is failed and NOT retryable. | |||
PhaseTwoCommitFailedCanNotRetry = 7; | |||
// The Phase two rollback completed. | |||
// description:Rollback logic is successfully done at phase two. | |||
PhaseTwoRolledBack = 8; | |||
// The Phase two rollback failed retryable. | |||
// description:Rollback logic is failed but retryable. | |||
PhaseTwoRollbackFailedRetryable = 9; | |||
// The Phase two rollback failed and can not retry. | |||
// description:Rollback logic is failed but NOT retryable. | |||
PhaseTwoRollbackFailedCanNotRetry = 10; | |||
} | |||
string Addressing = 1 [(gogoproto.moretags) = "xorm:\"addressing\""]; | |||
string XID = 2 [(gogoproto.moretags) = "xorm:\"xid\""]; | |||
int64 BranchID = 3 [(gogoproto.moretags) = "xorm:\"branch_id\""]; | |||
int64 TransactionID = 4 [(gogoproto.moretags) = "xorm:\"transaction_id\""]; | |||
string ResourceID = 5 [(gogoproto.moretags) = "xorm:\"resource_id\""]; | |||
string LockKey = 6 [(gogoproto.moretags) = "xorm:\"lock_key\""]; | |||
BranchType Type = 7 [(gogoproto.moretags) = "xorm:\"branch_type\""]; | |||
BranchStatus Status = 8 [(gogoproto.moretags) = "xorm:\"status\""]; | |||
bytes ApplicationData = 9 [(gogoproto.moretags) = "xorm:\"application_data\""]; | |||
bool AsyncCommit = 10 [(gogoproto.moretags) = "xorm:\"async_commit\""]; | |||
} | |||
message RowLock { | |||
string XID = 1 [(gogoproto.moretags) = "xorm:\"xid\""]; | |||
int64 TransactionID = 2 [(gogoproto.moretags) = "xorm:\"transaction_id\""]; | |||
int64 BranchID = 3 [(gogoproto.moretags) = "xorm:\"branch_id\""]; | |||
string ResourceID = 4 [(gogoproto.moretags) = "xorm:\"resource_id\""]; | |||
string TableName = 5 [(gogoproto.moretags) = "xorm:\"table_name\""]; | |||
string PK = 6 [(gogoproto.moretags) = "xorm:\"pk\""]; | |||
string RowKey = 7 [(gogoproto.moretags) = "xorm:\"row_key\""]; | |||
} | |||
// GlobalBeginRequest represents a global transaction begin | |||
message GlobalBeginRequest { | |||
string Addressing = 1; | |||
int32 Timeout = 2; | |||
string TransactionName = 3; | |||
} | |||
// GlobalBeginResponse represents a response to GlobalBeginRequest | |||
message GlobalBeginResponse { | |||
ResultCode ResultCode = 1; | |||
ExceptionCode ExceptionCode = 2; | |||
string Message = 3; | |||
string XID = 4; | |||
} | |||
// BranchRegisterRequest represents a branch transaction join in the global transaction | |||
message BranchRegisterRequest { | |||
string Addressing = 1; | |||
string XID = 2; | |||
string ResourceID = 3; | |||
string LockKey = 4; | |||
BranchSession.BranchType BranchType = 5; | |||
bytes ApplicationData = 6; | |||
bool AsyncCommit = 7; | |||
} | |||
// BranchRegisterResponse represents a response to BranchRegisterRequest | |||
message BranchRegisterResponse { | |||
ResultCode ResultCode = 1; | |||
ExceptionCode ExceptionCode = 2; | |||
string Message = 3; | |||
int64 BranchID = 4; | |||
} | |||
// BranchReportRequest represents a request to report branch transaction execution status | |||
message BranchReportRequest { | |||
string XID = 1; | |||
int64 BranchID = 2; | |||
string ResourceID = 3; | |||
BranchSession.BranchType BranchType = 4; | |||
BranchSession.BranchStatus BranchStatus = 5; | |||
bytes ApplicationData = 6; | |||
} | |||
// BranchReportResponse represents a response to BranchReportRequest | |||
message BranchReportResponse { | |||
ResultCode ResultCode = 1; | |||
ExceptionCode ExceptionCode = 2; | |||
string Message = 3; | |||
} | |||
// GlobalLockQueryRequest represents a request to query the global lock | |||
message GlobalLockQueryRequest { | |||
string XID = 1; | |||
string ResourceID = 2; | |||
string LockKey = 3; | |||
BranchSession.BranchType BranchType = 4; | |||
} | |||
// GlobalLockQueryResponse represents a response to GlobalLockQueryRequest | |||
message GlobalLockQueryResponse { | |||
ResultCode ResultCode = 1; | |||
ExceptionCode ExceptionCode = 2; | |||
string Message = 3; | |||
bool Lockable = 4; | |||
} | |||
// GlobalStatusRequest represents a request to query the global transaction status | |||
message GlobalStatusRequest { | |||
string XID = 1; | |||
} | |||
// GlobalStatusResponse represents a response to GlobalStatusRequest | |||
message GlobalStatusResponse { | |||
ResultCode ResultCode = 1; | |||
ExceptionCode ExceptionCode = 2; | |||
string Message = 3; | |||
GlobalSession.GlobalStatus GlobalStatus = 4; | |||
} | |||
// GlobalCommitRequest represents a request to commit global transaction | |||
message GlobalCommitRequest { | |||
string XID = 1; | |||
} | |||
// GlobalCommitResponse represents a response to GlobalCommitRequest | |||
message GlobalCommitResponse { | |||
ResultCode ResultCode = 1; | |||
ExceptionCode ExceptionCode = 2; | |||
string Message = 3; | |||
GlobalSession.GlobalStatus GlobalStatus = 4; | |||
} | |||
// GlobalRollbackRequest represents a request to rollback global transaction | |||
message GlobalRollbackRequest { | |||
string XID = 1; | |||
} | |||
// GlobalRollbackResponse represents a response to GlobalRollbackRequest | |||
message GlobalRollbackResponse { | |||
ResultCode ResultCode = 1; | |||
ExceptionCode ExceptionCode = 2; | |||
string Message = 3; | |||
GlobalSession.GlobalStatus GlobalStatus = 4; | |||
} | |||
// GlobalReportRequest represents a request to report global transaction execution status | |||
message GlobalReportRequest { | |||
string XID = 1; | |||
GlobalSession.GlobalStatus GlobalStatus = 2; | |||
} | |||
// GlobalReportResponse represents a response to GlobalReportRequest | |||
message GlobalReportResponse { | |||
ResultCode ResultCode = 1; | |||
ExceptionCode ExceptionCode = 2; | |||
string Message = 3; | |||
GlobalSession.GlobalStatus GlobalStatus = 4; | |||
} | |||
// BranchCommitRequest represents a request to commit branch transaction | |||
message BranchCommitRequest { | |||
string XID = 1; | |||
int64 BranchID = 2; | |||
string ResourceID = 3; | |||
string LockKey = 4; | |||
BranchSession.BranchType BranchType = 5; | |||
bytes ApplicationData = 6; | |||
} | |||
// BranchCommitResponse represents a response to BranchCommitRequest | |||
message BranchCommitResponse { | |||
ResultCode ResultCode = 1; | |||
ExceptionCode ExceptionCode = 2; | |||
string Message = 3; | |||
string XID = 4; | |||
int64 BranchID = 5; | |||
BranchSession.BranchStatus BranchStatus = 6; | |||
} | |||
// BranchCommitRequest represents a request to rollback branch transaction | |||
message BranchRollbackRequest { | |||
string XID = 1; | |||
int64 BranchID = 2; | |||
string ResourceID = 3; | |||
string LockKey = 4; | |||
BranchSession.BranchType BranchType = 5; | |||
bytes ApplicationData = 6; | |||
} | |||
// BranchRollbackResponse represents a response to BranchRollbackRequest | |||
message BranchRollbackResponse { | |||
ResultCode ResultCode = 1; | |||
ExceptionCode ExceptionCode = 2; | |||
string Message = 3; | |||
string XID = 4; | |||
int64 BranchID = 5; | |||
BranchSession.BranchStatus BranchStatus = 6; | |||
} | |||
message BranchMessage { | |||
int64 ID = 1; | |||
BranchMessageType BranchMessageType = 2; | |||
google.protobuf.Any Message = 3; | |||
} | |||
service TransactionManagerService { | |||
rpc Begin(GlobalBeginRequest) returns (GlobalBeginResponse); | |||
rpc GetStatus(GlobalStatusRequest) returns (GlobalStatusResponse); | |||
rpc GlobalReport(GlobalReportRequest) returns (GlobalReportResponse); | |||
rpc Commit(GlobalCommitRequest) returns (GlobalCommitResponse); | |||
rpc Rollback(GlobalRollbackRequest) returns (GlobalRollbackResponse); | |||
} | |||
service ResourceManagerService { | |||
rpc BranchCommunicate(stream BranchMessage) returns (stream BranchMessage); | |||
rpc BranchRegister(BranchRegisterRequest) returns (BranchRegisterResponse); | |||
rpc BranchReport(BranchReportRequest) returns (BranchReportResponse); | |||
rpc LockQuery(GlobalLockQueryRequest) returns (GlobalLockQueryResponse); | |||
} | |||
@@ -0,0 +1,468 @@ | |||
// Code generated by protoc-gen-go-grpc. DO NOT EDIT. | |||
package apis | |||
import ( | |||
context "context" | |||
grpc "google.golang.org/grpc" | |||
codes "google.golang.org/grpc/codes" | |||
status "google.golang.org/grpc/status" | |||
) | |||
// This is a compile-time assertion to ensure that this generated file | |||
// is compatible with the grpc package it is being compiled against. | |||
// Requires gRPC-Go v1.32.0 or later. | |||
const _ = grpc.SupportPackageIsVersion7 | |||
// TransactionManagerServiceClient is the client API for TransactionManagerService service. | |||
// | |||
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. | |||
type TransactionManagerServiceClient interface { | |||
Begin(ctx context.Context, in *GlobalBeginRequest, opts ...grpc.CallOption) (*GlobalBeginResponse, error) | |||
GetStatus(ctx context.Context, in *GlobalStatusRequest, opts ...grpc.CallOption) (*GlobalStatusResponse, error) | |||
GlobalReport(ctx context.Context, in *GlobalReportRequest, opts ...grpc.CallOption) (*GlobalReportResponse, error) | |||
Commit(ctx context.Context, in *GlobalCommitRequest, opts ...grpc.CallOption) (*GlobalCommitResponse, error) | |||
Rollback(ctx context.Context, in *GlobalRollbackRequest, opts ...grpc.CallOption) (*GlobalRollbackResponse, error) | |||
} | |||
type transactionManagerServiceClient struct { | |||
cc grpc.ClientConnInterface | |||
} | |||
func NewTransactionManagerServiceClient(cc grpc.ClientConnInterface) TransactionManagerServiceClient { | |||
return &transactionManagerServiceClient{cc} | |||
} | |||
func (c *transactionManagerServiceClient) Begin(ctx context.Context, in *GlobalBeginRequest, opts ...grpc.CallOption) (*GlobalBeginResponse, error) { | |||
out := new(GlobalBeginResponse) | |||
err := c.cc.Invoke(ctx, "/apis.TransactionManagerService/Begin", in, out, opts...) | |||
if err != nil { | |||
return nil, err | |||
} | |||
return out, nil | |||
} | |||
func (c *transactionManagerServiceClient) GetStatus(ctx context.Context, in *GlobalStatusRequest, opts ...grpc.CallOption) (*GlobalStatusResponse, error) { | |||
out := new(GlobalStatusResponse) | |||
err := c.cc.Invoke(ctx, "/apis.TransactionManagerService/GetStatus", in, out, opts...) | |||
if err != nil { | |||
return nil, err | |||
} | |||
return out, nil | |||
} | |||
func (c *transactionManagerServiceClient) GlobalReport(ctx context.Context, in *GlobalReportRequest, opts ...grpc.CallOption) (*GlobalReportResponse, error) { | |||
out := new(GlobalReportResponse) | |||
err := c.cc.Invoke(ctx, "/apis.TransactionManagerService/GlobalReport", in, out, opts...) | |||
if err != nil { | |||
return nil, err | |||
} | |||
return out, nil | |||
} | |||
func (c *transactionManagerServiceClient) Commit(ctx context.Context, in *GlobalCommitRequest, opts ...grpc.CallOption) (*GlobalCommitResponse, error) { | |||
out := new(GlobalCommitResponse) | |||
err := c.cc.Invoke(ctx, "/apis.TransactionManagerService/Commit", in, out, opts...) | |||
if err != nil { | |||
return nil, err | |||
} | |||
return out, nil | |||
} | |||
func (c *transactionManagerServiceClient) Rollback(ctx context.Context, in *GlobalRollbackRequest, opts ...grpc.CallOption) (*GlobalRollbackResponse, error) { | |||
out := new(GlobalRollbackResponse) | |||
err := c.cc.Invoke(ctx, "/apis.TransactionManagerService/Rollback", in, out, opts...) | |||
if err != nil { | |||
return nil, err | |||
} | |||
return out, nil | |||
} | |||
// TransactionManagerServiceServer is the server API for TransactionManagerService service. | |||
// All implementations should embed UnimplementedTransactionManagerServiceServer | |||
// for forward compatibility | |||
type TransactionManagerServiceServer interface { | |||
Begin(context.Context, *GlobalBeginRequest) (*GlobalBeginResponse, error) | |||
GetStatus(context.Context, *GlobalStatusRequest) (*GlobalStatusResponse, error) | |||
GlobalReport(context.Context, *GlobalReportRequest) (*GlobalReportResponse, error) | |||
Commit(context.Context, *GlobalCommitRequest) (*GlobalCommitResponse, error) | |||
Rollback(context.Context, *GlobalRollbackRequest) (*GlobalRollbackResponse, error) | |||
} | |||
// UnimplementedTransactionManagerServiceServer should be embedded to have forward compatible implementations. | |||
type UnimplementedTransactionManagerServiceServer struct { | |||
} | |||
func (UnimplementedTransactionManagerServiceServer) Begin(context.Context, *GlobalBeginRequest) (*GlobalBeginResponse, error) { | |||
return nil, status.Errorf(codes.Unimplemented, "method Begin not implemented") | |||
} | |||
func (UnimplementedTransactionManagerServiceServer) GetStatus(context.Context, *GlobalStatusRequest) (*GlobalStatusResponse, error) { | |||
return nil, status.Errorf(codes.Unimplemented, "method GetStatus not implemented") | |||
} | |||
func (UnimplementedTransactionManagerServiceServer) GlobalReport(context.Context, *GlobalReportRequest) (*GlobalReportResponse, error) { | |||
return nil, status.Errorf(codes.Unimplemented, "method GlobalReport not implemented") | |||
} | |||
func (UnimplementedTransactionManagerServiceServer) Commit(context.Context, *GlobalCommitRequest) (*GlobalCommitResponse, error) { | |||
return nil, status.Errorf(codes.Unimplemented, "method Commit not implemented") | |||
} | |||
func (UnimplementedTransactionManagerServiceServer) Rollback(context.Context, *GlobalRollbackRequest) (*GlobalRollbackResponse, error) { | |||
return nil, status.Errorf(codes.Unimplemented, "method Rollback not implemented") | |||
} | |||
// UnsafeTransactionManagerServiceServer may be embedded to opt out of forward compatibility for this service. | |||
// Use of this interface is not recommended, as added methods to TransactionManagerServiceServer will | |||
// result in compilation errors. | |||
type UnsafeTransactionManagerServiceServer interface { | |||
mustEmbedUnimplementedTransactionManagerServiceServer() | |||
} | |||
func RegisterTransactionManagerServiceServer(s grpc.ServiceRegistrar, srv TransactionManagerServiceServer) { | |||
s.RegisterService(&TransactionManagerService_ServiceDesc, srv) | |||
} | |||
func _TransactionManagerService_Begin_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { | |||
in := new(GlobalBeginRequest) | |||
if err := dec(in); err != nil { | |||
return nil, err | |||
} | |||
if interceptor == nil { | |||
return srv.(TransactionManagerServiceServer).Begin(ctx, in) | |||
} | |||
info := &grpc.UnaryServerInfo{ | |||
Server: srv, | |||
FullMethod: "/apis.TransactionManagerService/Begin", | |||
} | |||
handler := func(ctx context.Context, req interface{}) (interface{}, error) { | |||
return srv.(TransactionManagerServiceServer).Begin(ctx, req.(*GlobalBeginRequest)) | |||
} | |||
return interceptor(ctx, in, info, handler) | |||
} | |||
func _TransactionManagerService_GetStatus_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { | |||
in := new(GlobalStatusRequest) | |||
if err := dec(in); err != nil { | |||
return nil, err | |||
} | |||
if interceptor == nil { | |||
return srv.(TransactionManagerServiceServer).GetStatus(ctx, in) | |||
} | |||
info := &grpc.UnaryServerInfo{ | |||
Server: srv, | |||
FullMethod: "/apis.TransactionManagerService/GetStatus", | |||
} | |||
handler := func(ctx context.Context, req interface{}) (interface{}, error) { | |||
return srv.(TransactionManagerServiceServer).GetStatus(ctx, req.(*GlobalStatusRequest)) | |||
} | |||
return interceptor(ctx, in, info, handler) | |||
} | |||
func _TransactionManagerService_GlobalReport_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { | |||
in := new(GlobalReportRequest) | |||
if err := dec(in); err != nil { | |||
return nil, err | |||
} | |||
if interceptor == nil { | |||
return srv.(TransactionManagerServiceServer).GlobalReport(ctx, in) | |||
} | |||
info := &grpc.UnaryServerInfo{ | |||
Server: srv, | |||
FullMethod: "/apis.TransactionManagerService/GlobalReport", | |||
} | |||
handler := func(ctx context.Context, req interface{}) (interface{}, error) { | |||
return srv.(TransactionManagerServiceServer).GlobalReport(ctx, req.(*GlobalReportRequest)) | |||
} | |||
return interceptor(ctx, in, info, handler) | |||
} | |||
func _TransactionManagerService_Commit_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { | |||
in := new(GlobalCommitRequest) | |||
if err := dec(in); err != nil { | |||
return nil, err | |||
} | |||
if interceptor == nil { | |||
return srv.(TransactionManagerServiceServer).Commit(ctx, in) | |||
} | |||
info := &grpc.UnaryServerInfo{ | |||
Server: srv, | |||
FullMethod: "/apis.TransactionManagerService/Commit", | |||
} | |||
handler := func(ctx context.Context, req interface{}) (interface{}, error) { | |||
return srv.(TransactionManagerServiceServer).Commit(ctx, req.(*GlobalCommitRequest)) | |||
} | |||
return interceptor(ctx, in, info, handler) | |||
} | |||
func _TransactionManagerService_Rollback_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { | |||
in := new(GlobalRollbackRequest) | |||
if err := dec(in); err != nil { | |||
return nil, err | |||
} | |||
if interceptor == nil { | |||
return srv.(TransactionManagerServiceServer).Rollback(ctx, in) | |||
} | |||
info := &grpc.UnaryServerInfo{ | |||
Server: srv, | |||
FullMethod: "/apis.TransactionManagerService/Rollback", | |||
} | |||
handler := func(ctx context.Context, req interface{}) (interface{}, error) { | |||
return srv.(TransactionManagerServiceServer).Rollback(ctx, req.(*GlobalRollbackRequest)) | |||
} | |||
return interceptor(ctx, in, info, handler) | |||
} | |||
// TransactionManagerService_ServiceDesc is the grpc.ServiceDesc for TransactionManagerService service. | |||
// It's only intended for direct use with grpc.RegisterService, | |||
// and not to be introspected or modified (even as a copy) | |||
var TransactionManagerService_ServiceDesc = grpc.ServiceDesc{ | |||
ServiceName: "apis.TransactionManagerService", | |||
HandlerType: (*TransactionManagerServiceServer)(nil), | |||
Methods: []grpc.MethodDesc{ | |||
{ | |||
MethodName: "Begin", | |||
Handler: _TransactionManagerService_Begin_Handler, | |||
}, | |||
{ | |||
MethodName: "GetStatus", | |||
Handler: _TransactionManagerService_GetStatus_Handler, | |||
}, | |||
{ | |||
MethodName: "GlobalReport", | |||
Handler: _TransactionManagerService_GlobalReport_Handler, | |||
}, | |||
{ | |||
MethodName: "Commit", | |||
Handler: _TransactionManagerService_Commit_Handler, | |||
}, | |||
{ | |||
MethodName: "Rollback", | |||
Handler: _TransactionManagerService_Rollback_Handler, | |||
}, | |||
}, | |||
Streams: []grpc.StreamDesc{}, | |||
Metadata: "seata.proto", | |||
} | |||
// ResourceManagerServiceClient is the client API for ResourceManagerService service. | |||
// | |||
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. | |||
type ResourceManagerServiceClient interface { | |||
BranchCommunicate(ctx context.Context, opts ...grpc.CallOption) (ResourceManagerService_BranchCommunicateClient, error) | |||
BranchRegister(ctx context.Context, in *BranchRegisterRequest, opts ...grpc.CallOption) (*BranchRegisterResponse, error) | |||
BranchReport(ctx context.Context, in *BranchReportRequest, opts ...grpc.CallOption) (*BranchReportResponse, error) | |||
LockQuery(ctx context.Context, in *GlobalLockQueryRequest, opts ...grpc.CallOption) (*GlobalLockQueryResponse, error) | |||
} | |||
type resourceManagerServiceClient struct { | |||
cc grpc.ClientConnInterface | |||
} | |||
func NewResourceManagerServiceClient(cc grpc.ClientConnInterface) ResourceManagerServiceClient { | |||
return &resourceManagerServiceClient{cc} | |||
} | |||
func (c *resourceManagerServiceClient) BranchCommunicate(ctx context.Context, opts ...grpc.CallOption) (ResourceManagerService_BranchCommunicateClient, error) { | |||
stream, err := c.cc.NewStream(ctx, &ResourceManagerService_ServiceDesc.Streams[0], "/apis.ResourceManagerService/BranchCommunicate", opts...) | |||
if err != nil { | |||
return nil, err | |||
} | |||
x := &resourceManagerServiceBranchCommunicateClient{stream} | |||
return x, nil | |||
} | |||
type ResourceManagerService_BranchCommunicateClient interface { | |||
Send(*BranchMessage) error | |||
Recv() (*BranchMessage, error) | |||
grpc.ClientStream | |||
} | |||
type resourceManagerServiceBranchCommunicateClient struct { | |||
grpc.ClientStream | |||
} | |||
func (x *resourceManagerServiceBranchCommunicateClient) Send(m *BranchMessage) error { | |||
return x.ClientStream.SendMsg(m) | |||
} | |||
func (x *resourceManagerServiceBranchCommunicateClient) Recv() (*BranchMessage, error) { | |||
m := new(BranchMessage) | |||
if err := x.ClientStream.RecvMsg(m); err != nil { | |||
return nil, err | |||
} | |||
return m, nil | |||
} | |||
func (c *resourceManagerServiceClient) BranchRegister(ctx context.Context, in *BranchRegisterRequest, opts ...grpc.CallOption) (*BranchRegisterResponse, error) { | |||
out := new(BranchRegisterResponse) | |||
err := c.cc.Invoke(ctx, "/apis.ResourceManagerService/BranchRegister", in, out, opts...) | |||
if err != nil { | |||
return nil, err | |||
} | |||
return out, nil | |||
} | |||
func (c *resourceManagerServiceClient) BranchReport(ctx context.Context, in *BranchReportRequest, opts ...grpc.CallOption) (*BranchReportResponse, error) { | |||
out := new(BranchReportResponse) | |||
err := c.cc.Invoke(ctx, "/apis.ResourceManagerService/BranchReport", in, out, opts...) | |||
if err != nil { | |||
return nil, err | |||
} | |||
return out, nil | |||
} | |||
func (c *resourceManagerServiceClient) LockQuery(ctx context.Context, in *GlobalLockQueryRequest, opts ...grpc.CallOption) (*GlobalLockQueryResponse, error) { | |||
out := new(GlobalLockQueryResponse) | |||
err := c.cc.Invoke(ctx, "/apis.ResourceManagerService/LockQuery", in, out, opts...) | |||
if err != nil { | |||
return nil, err | |||
} | |||
return out, nil | |||
} | |||
// ResourceManagerServiceServer is the server API for ResourceManagerService service. | |||
// All implementations should embed UnimplementedResourceManagerServiceServer | |||
// for forward compatibility | |||
type ResourceManagerServiceServer interface { | |||
BranchCommunicate(ResourceManagerService_BranchCommunicateServer) error | |||
BranchRegister(context.Context, *BranchRegisterRequest) (*BranchRegisterResponse, error) | |||
BranchReport(context.Context, *BranchReportRequest) (*BranchReportResponse, error) | |||
LockQuery(context.Context, *GlobalLockQueryRequest) (*GlobalLockQueryResponse, error) | |||
} | |||
// UnimplementedResourceManagerServiceServer should be embedded to have forward compatible implementations. | |||
type UnimplementedResourceManagerServiceServer struct { | |||
} | |||
func (UnimplementedResourceManagerServiceServer) BranchCommunicate(ResourceManagerService_BranchCommunicateServer) error { | |||
return status.Errorf(codes.Unimplemented, "method BranchCommunicate not implemented") | |||
} | |||
func (UnimplementedResourceManagerServiceServer) BranchRegister(context.Context, *BranchRegisterRequest) (*BranchRegisterResponse, error) { | |||
return nil, status.Errorf(codes.Unimplemented, "method BranchRegister not implemented") | |||
} | |||
func (UnimplementedResourceManagerServiceServer) BranchReport(context.Context, *BranchReportRequest) (*BranchReportResponse, error) { | |||
return nil, status.Errorf(codes.Unimplemented, "method BranchReport not implemented") | |||
} | |||
func (UnimplementedResourceManagerServiceServer) LockQuery(context.Context, *GlobalLockQueryRequest) (*GlobalLockQueryResponse, error) { | |||
return nil, status.Errorf(codes.Unimplemented, "method LockQuery not implemented") | |||
} | |||
// UnsafeResourceManagerServiceServer may be embedded to opt out of forward compatibility for this service. | |||
// Use of this interface is not recommended, as added methods to ResourceManagerServiceServer will | |||
// result in compilation errors. | |||
type UnsafeResourceManagerServiceServer interface { | |||
mustEmbedUnimplementedResourceManagerServiceServer() | |||
} | |||
func RegisterResourceManagerServiceServer(s grpc.ServiceRegistrar, srv ResourceManagerServiceServer) { | |||
s.RegisterService(&ResourceManagerService_ServiceDesc, srv) | |||
} | |||
func _ResourceManagerService_BranchCommunicate_Handler(srv interface{}, stream grpc.ServerStream) error { | |||
return srv.(ResourceManagerServiceServer).BranchCommunicate(&resourceManagerServiceBranchCommunicateServer{stream}) | |||
} | |||
type ResourceManagerService_BranchCommunicateServer interface { | |||
Send(*BranchMessage) error | |||
Recv() (*BranchMessage, error) | |||
grpc.ServerStream | |||
} | |||
type resourceManagerServiceBranchCommunicateServer struct { | |||
grpc.ServerStream | |||
} | |||
func (x *resourceManagerServiceBranchCommunicateServer) Send(m *BranchMessage) error { | |||
return x.ServerStream.SendMsg(m) | |||
} | |||
func (x *resourceManagerServiceBranchCommunicateServer) Recv() (*BranchMessage, error) { | |||
m := new(BranchMessage) | |||
if err := x.ServerStream.RecvMsg(m); err != nil { | |||
return nil, err | |||
} | |||
return m, nil | |||
} | |||
func _ResourceManagerService_BranchRegister_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { | |||
in := new(BranchRegisterRequest) | |||
if err := dec(in); err != nil { | |||
return nil, err | |||
} | |||
if interceptor == nil { | |||
return srv.(ResourceManagerServiceServer).BranchRegister(ctx, in) | |||
} | |||
info := &grpc.UnaryServerInfo{ | |||
Server: srv, | |||
FullMethod: "/apis.ResourceManagerService/BranchRegister", | |||
} | |||
handler := func(ctx context.Context, req interface{}) (interface{}, error) { | |||
return srv.(ResourceManagerServiceServer).BranchRegister(ctx, req.(*BranchRegisterRequest)) | |||
} | |||
return interceptor(ctx, in, info, handler) | |||
} | |||
func _ResourceManagerService_BranchReport_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { | |||
in := new(BranchReportRequest) | |||
if err := dec(in); err != nil { | |||
return nil, err | |||
} | |||
if interceptor == nil { | |||
return srv.(ResourceManagerServiceServer).BranchReport(ctx, in) | |||
} | |||
info := &grpc.UnaryServerInfo{ | |||
Server: srv, | |||
FullMethod: "/apis.ResourceManagerService/BranchReport", | |||
} | |||
handler := func(ctx context.Context, req interface{}) (interface{}, error) { | |||
return srv.(ResourceManagerServiceServer).BranchReport(ctx, req.(*BranchReportRequest)) | |||
} | |||
return interceptor(ctx, in, info, handler) | |||
} | |||
func _ResourceManagerService_LockQuery_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { | |||
in := new(GlobalLockQueryRequest) | |||
if err := dec(in); err != nil { | |||
return nil, err | |||
} | |||
if interceptor == nil { | |||
return srv.(ResourceManagerServiceServer).LockQuery(ctx, in) | |||
} | |||
info := &grpc.UnaryServerInfo{ | |||
Server: srv, | |||
FullMethod: "/apis.ResourceManagerService/LockQuery", | |||
} | |||
handler := func(ctx context.Context, req interface{}) (interface{}, error) { | |||
return srv.(ResourceManagerServiceServer).LockQuery(ctx, req.(*GlobalLockQueryRequest)) | |||
} | |||
return interceptor(ctx, in, info, handler) | |||
} | |||
// ResourceManagerService_ServiceDesc is the grpc.ServiceDesc for ResourceManagerService service. | |||
// It's only intended for direct use with grpc.RegisterService, | |||
// and not to be introspected or modified (even as a copy) | |||
var ResourceManagerService_ServiceDesc = grpc.ServiceDesc{ | |||
ServiceName: "apis.ResourceManagerService", | |||
HandlerType: (*ResourceManagerServiceServer)(nil), | |||
Methods: []grpc.MethodDesc{ | |||
{ | |||
MethodName: "BranchRegister", | |||
Handler: _ResourceManagerService_BranchRegister_Handler, | |||
}, | |||
{ | |||
MethodName: "BranchReport", | |||
Handler: _ResourceManagerService_BranchReport_Handler, | |||
}, | |||
{ | |||
MethodName: "LockQuery", | |||
Handler: _ResourceManagerService_LockQuery_Handler, | |||
}, | |||
}, | |||
Streams: []grpc.StreamDesc{ | |||
{ | |||
StreamName: "BranchCommunicate", | |||
Handler: _ResourceManagerService_BranchCommunicate_Handler, | |||
ServerStreams: true, | |||
ClientStreams: true, | |||
}, | |||
}, | |||
Metadata: "seata.proto", | |||
} |
@@ -0,0 +1,11 @@ | |||
package context | |||
// BusinessActionContext store the tcc branch transaction context | |||
type BusinessActionContext struct { | |||
*RootContext | |||
XID string | |||
BranchID int64 | |||
ActionName string | |||
ActionContext map[string]interface{} | |||
AsyncCommit bool | |||
} |
@@ -0,0 +1,151 @@ | |||
package context | |||
import ( | |||
"context" | |||
"fmt" | |||
"strings" | |||
"github.com/opentrx/seata-golang/v2/pkg/apis" | |||
"github.com/opentrx/seata-golang/v2/pkg/util/log" | |||
) | |||
const ( | |||
KeyXID = "TX_XID" | |||
KeyXIDInterceptorType = "tx-xid-interceptor-type" | |||
KeyGlobalLockFlag = "TX_LOCK" | |||
) | |||
// RootContext store the global transaction context | |||
type RootContext struct { | |||
context.Context | |||
// like thread local map | |||
localMap map[string]interface{} | |||
} | |||
// NewRootContext return a pointer to RootContext | |||
func NewRootContext(ctx context.Context) *RootContext { | |||
rootCtx := &RootContext{ | |||
Context: ctx, | |||
localMap: make(map[string]interface{}), | |||
} | |||
xID := ctx.Value(KeyXID) | |||
if xID != nil { | |||
xid := xID.(string) | |||
rootCtx.Bind(xid) | |||
} | |||
return rootCtx | |||
} | |||
// Set store key value to RootContext | |||
func (c *RootContext) Set(key string, value interface{}) { | |||
if c.localMap == nil { | |||
c.localMap = make(map[string]interface{}) | |||
} | |||
c.localMap[key] = value | |||
} | |||
// Get get a value by given key from RootContext | |||
func (c *RootContext) Get(key string) (value interface{}, exists bool) { | |||
value, exists = c.localMap[key] | |||
return | |||
} | |||
// GetXID from RootContext get xid | |||
func (c *RootContext) GetXID() string { | |||
xID := c.localMap[KeyXID] | |||
xid, ok := xID.(string) | |||
if ok && xid != "" { | |||
return xid | |||
} | |||
xIDType := c.localMap[KeyXIDInterceptorType] | |||
xidType, success := xIDType.(string) | |||
if success && xidType != "" && strings.Contains(xidType, "_") { | |||
return strings.Split(xidType, "_")[0] | |||
} | |||
return "" | |||
} | |||
// GetXIDInterceptorType from RootContext get xid interceptor type | |||
func (c *RootContext) GetXIDInterceptorType() string { | |||
xIDType := c.localMap[KeyXIDInterceptorType] | |||
xidType, _ := xIDType.(string) | |||
return xidType | |||
} | |||
// Bind bind xid with RootContext | |||
func (c *RootContext) Bind(xid string) { | |||
log.Debugf("bind %s", xid) | |||
c.Set(KeyXID, xid) | |||
} | |||
// BindInterceptorType bind interceptor type with RootContext | |||
func (c *RootContext) BindInterceptorType(xidType string) { | |||
if xidType != "" { | |||
xidTypes := strings.Split(xidType, "_") | |||
if len(xidTypes) == 2 { | |||
c.BindInterceptorTypeWithBranchType(xidTypes[0], | |||
apis.BranchSession_BranchType(apis.BranchSession_BranchType_value[xidTypes[1]])) | |||
} | |||
} | |||
} | |||
// BindInterceptorTypeWithBranchType bind interceptor type and branch type with RootContext | |||
func (c *RootContext) BindInterceptorTypeWithBranchType(xid string, branchType apis.BranchSession_BranchType) { | |||
xidType := fmt.Sprintf("%s_%s", xid, branchType.String()) | |||
log.Debugf("bind interceptor type xid=%s branchType=%s", xid, branchType.String()) | |||
c.Set(KeyXIDInterceptorType, xidType) | |||
} | |||
// BindGlobalLockFlag bind global lock flag with RootContext | |||
func (c *RootContext) BindGlobalLockFlag() { | |||
log.Debug("local transaction global lock support enabled") | |||
c.Set(KeyGlobalLockFlag, KeyGlobalLockFlag) | |||
} | |||
// Unbind unbind xid with RootContext | |||
func (c *RootContext) Unbind() string { | |||
xID := c.localMap[KeyXID] | |||
xid, ok := xID.(string) | |||
if ok && xid != "" { | |||
log.Debugf("unbind %s", xid) | |||
delete(c.localMap, KeyXID) | |||
return xid | |||
} | |||
return "" | |||
} | |||
// UnbindInterceptorType unbind interceptor type with RootContext | |||
func (c *RootContext) UnbindInterceptorType() string { | |||
xidType := c.localMap[KeyXIDInterceptorType] | |||
xt, ok := xidType.(string) | |||
if ok && xt != "" { | |||
log.Debugf("unbind inteceptor type %s", xidType) | |||
delete(c.localMap, KeyXIDInterceptorType) | |||
return xt | |||
} | |||
return "" | |||
} | |||
// UnbindGlobalLockFlag unbind global lock flag with RootContext | |||
func (c *RootContext) UnbindGlobalLockFlag() { | |||
log.Debug("unbind global lock flag") | |||
delete(c.localMap, KeyGlobalLockFlag) | |||
} | |||
// InGlobalTransaction determine whether the context is in global transaction | |||
func (c *RootContext) InGlobalTransaction() bool { | |||
return c.localMap[KeyXID] != nil | |||
} | |||
// RequireGlobalLock return global lock flag | |||
func (c *RootContext) RequireGlobalLock() bool { | |||
_, exists := c.localMap[KeyGlobalLockFlag] | |||
return exists | |||
} |
@@ -0,0 +1,56 @@ | |||
package exception | |||
import ( | |||
"errors" | |||
"github.com/opentrx/seata-golang/v2/pkg/apis" | |||
) | |||
// TransactionException | |||
type TransactionException struct { | |||
Code apis.ExceptionCode | |||
Message string | |||
Err error | |||
} | |||
// Error | |||
func (e *TransactionException) Error() string { | |||
return "TransactionException: " + e.Message | |||
} | |||
// Unwrap | |||
func (e *TransactionException) Unwrap() error { return e.Err } | |||
// TransactionExceptionOption for edit TransactionException | |||
type TransactionExceptionOption func(exception *TransactionException) | |||
// WithExceptionCode edit exception code in TransactionException | |||
func WithExceptionCode(code apis.ExceptionCode) TransactionExceptionOption { | |||
return func(exception *TransactionException) { | |||
exception.Code = code | |||
} | |||
} | |||
// WithMessage edit message in TransactionException | |||
func WithMessage(message string) TransactionExceptionOption { | |||
return func(exception *TransactionException) { | |||
exception.Message = message | |||
} | |||
} | |||
// NewTransactionException return a pointer to TransactionException | |||
func NewTransactionException(err error, opts ...TransactionExceptionOption) *TransactionException { | |||
var ex *TransactionException | |||
if errors.As(err, &ex) { | |||
return ex | |||
} | |||
ex = &TransactionException{ | |||
Code: apis.UnknownErr, | |||
Message: err.Error(), | |||
Err: err, | |||
} | |||
for _, o := range opts { | |||
o(ex) | |||
} | |||
return ex | |||
} |
@@ -0,0 +1,12 @@ | |||
package model | |||
import ( | |||
"github.com/opentrx/seata-golang/v2/pkg/apis" | |||
) | |||
// Resource used to manage transaction resource | |||
type Resource interface { | |||
GetResourceID() string | |||
GetBranchType() apis.BranchSession_BranchType | |||
} |
@@ -0,0 +1,47 @@ | |||
package model | |||
import "fmt" | |||
// Propagation transaction isolation level | |||
type Propagation byte | |||
const ( | |||
Required Propagation = iota | |||
RequiresNew | |||
NotSupported | |||
Supports | |||
Never | |||
Mandatory | |||
) | |||
// String | |||
func (t Propagation) String() string { | |||
switch t { | |||
case Required: | |||
return "Required" | |||
case RequiresNew: | |||
return "REQUIRES_NEW" | |||
case NotSupported: | |||
return "NOT_SUPPORTED" | |||
case Supports: | |||
return "Supports" | |||
case Never: | |||
return "Never" | |||
case Mandatory: | |||
return "Mandatory" | |||
default: | |||
return fmt.Sprintf("%d", t) | |||
} | |||
} | |||
// TransactionInfo used to configure global transaction parameters | |||
type TransactionInfo struct { | |||
TimeOut int32 | |||
Name string | |||
Propagation Propagation | |||
} |
@@ -1,107 +1,39 @@ | |||
/* | |||
* Licensed to the Apache Software Foundation (ASF) under one or more | |||
* contributor license agreements. See the NOTICE file distributed with | |||
* this work for additional information regarding copyright ownership. | |||
* The ASF licenses this file to You under the Apache License, Version 2.0 | |||
* (the "License"); you may not use this file except in compliance with | |||
* the License. You may obtain a copy of the License at | |||
* | |||
* http://www.apache.org/licenses/LICENSE-2.0 | |||
* | |||
* Unless required by applicable law or agreed to in writing, software | |||
* distributed under the License is distributed on an "AS IS" BASIS, | |||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
* See the License for the specific language governing permissions and | |||
* limitations under the License. | |||
*/ | |||
package client | |||
import ( | |||
"sync" | |||
"seata.apache.org/seata-go/pkg/datasource" | |||
at "seata.apache.org/seata-go/pkg/datasource/sql" | |||
"seata.apache.org/seata-go/pkg/datasource/sql/exec/config" | |||
"seata.apache.org/seata-go/pkg/discovery" | |||
"seata.apache.org/seata-go/pkg/integration" | |||
remoteConfig "seata.apache.org/seata-go/pkg/remoting/config" | |||
"seata.apache.org/seata-go/pkg/remoting/getty" | |||
"seata.apache.org/seata-go/pkg/remoting/processor/client" | |||
"seata.apache.org/seata-go/pkg/rm" | |||
"seata.apache.org/seata-go/pkg/rm/tcc" | |||
"seata.apache.org/seata-go/pkg/tm" | |||
"seata.apache.org/seata-go/pkg/util/log" | |||
) | |||
"log" | |||
// Init seata client client | |||
func Init() { | |||
InitPath("") | |||
} | |||
"google.golang.org/grpc" | |||
// InitPath init client with config path | |||
func InitPath(configFilePath string) { | |||
cfg := LoadPath(configFilePath) | |||
initRegistry(cfg) | |||
initRmClient(cfg) | |||
initTmClient(cfg) | |||
initDatasource() | |||
} | |||
var ( | |||
onceInitTmClient sync.Once | |||
onceInitRmClient sync.Once | |||
onceInitDatasource sync.Once | |||
onceInitRegistry sync.Once | |||
"github.com/opentrx/seata-golang/v2/pkg/apis" | |||
"github.com/opentrx/seata-golang/v2/pkg/client/config" | |||
"github.com/opentrx/seata-golang/v2/pkg/client/rm" | |||
"github.com/opentrx/seata-golang/v2/pkg/client/tcc" | |||
"github.com/opentrx/seata-golang/v2/pkg/client/tm" | |||
) | |||
// InitTmClient init client tm client | |||
func initTmClient(cfg *Config) { | |||
onceInitTmClient.Do(func() { | |||
tm.InitTm(cfg.ClientConfig.TmConfig) | |||
}) | |||
} | |||
// initRemoting init remoting | |||
func initRemoting(cfg *Config) { | |||
seataConfig := remoteConfig.SeataConfig{ | |||
ApplicationID: cfg.ApplicationID, | |||
TxServiceGroup: cfg.TxServiceGroup, | |||
ServiceVgroupMapping: cfg.ServiceConfig.VgroupMapping, | |||
ServiceGrouplist: cfg.ServiceConfig.Grouplist, | |||
LoadBalanceType: cfg.GettyConfig.LoadBalanceType, | |||
// Init init resource manager,init transaction manager, expose a port to listen tc | |||
// call back request. | |||
func Init(config *config.Configuration) { | |||
var conn *grpc.ClientConn | |||
var err error | |||
if config.GetClientTLS() == nil { | |||
conn, err = grpc.Dial(config.ServerAddressing, | |||
grpc.WithInsecure(), | |||
grpc.WithKeepaliveParams(config.GetClientParameters())) | |||
} else { | |||
conn, err = grpc.Dial(config.ServerAddressing, | |||
grpc.WithKeepaliveParams(config.GetClientParameters()), grpc.WithTransportCredentials(config.GetClientTLS())) | |||
} | |||
getty.InitGetty(&cfg.GettyConfig, &seataConfig) | |||
} | |||
// InitRmClient init client rm client | |||
func initRmClient(cfg *Config) { | |||
onceInitRmClient.Do(func() { | |||
log.Init() | |||
initRemoting(cfg) | |||
rm.InitRm(rm.RmConfig{ | |||
Config: cfg.ClientConfig.RmConfig, | |||
ApplicationID: cfg.ApplicationID, | |||
TxServiceGroup: cfg.TxServiceGroup, | |||
}) | |||
config.Init(cfg.ClientConfig.RmConfig.LockConfig) | |||
client.RegisterProcessor() | |||
integration.Init() | |||
tcc.InitTCC(cfg.TCCConfig.FenceConfig) | |||
at.InitAT(cfg.ClientConfig.UndoConfig, cfg.AsyncWorkerConfig) | |||
at.InitXA(cfg.ClientConfig.XaConfig) | |||
}) | |||
} | |||
if err != nil { | |||
log.Fatalf("did not connect: %v", err) | |||
} | |||
func initDatasource() { | |||
onceInitDatasource.Do(func() { | |||
datasource.Init() | |||
}) | |||
} | |||
resourceManagerClient := apis.NewResourceManagerServiceClient(conn) | |||
transactionManagerClient := apis.NewTransactionManagerServiceClient(conn) | |||
func initRegistry(cfg *Config) { | |||
onceInitRegistry.Do(func() { | |||
discovery.InitRegistry(&cfg.ServiceConfig, &cfg.RegistryConfig) | |||
}) | |||
rm.InitResourceManager(config.Addressing, resourceManagerClient) | |||
tm.InitTransactionManager(config.Addressing, transactionManagerClient) | |||
rm.RegisterTransactionServiceServer(tcc.GetTCCResourceManager()) | |||
} |
@@ -1,254 +0,0 @@ | |||
/* | |||
* Licensed to the Apache Software Foundation (ASF) under one or more | |||
* contributor license agreements. See the NOTICE file distributed with | |||
* this work for additional information regarding copyright ownership. | |||
* The ASF licenses this file to You under the Apache License, Version 2.0 | |||
* (the "License"); you may not use this file except in compliance with | |||
* the License. You may obtain a copy of the License at | |||
* | |||
* http://www.apache.org/licenses/LICENSE-2.0 | |||
* | |||
* Unless required by applicable law or agreed to in writing, software | |||
* distributed under the License is distributed on an "AS IS" BASIS, | |||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
* See the License for the specific language governing permissions and | |||
* limitations under the License. | |||
*/ | |||
package client | |||
import ( | |||
"flag" | |||
"fmt" | |||
"io/ioutil" | |||
"os" | |||
"path/filepath" | |||
"runtime" | |||
"strings" | |||
"github.com/knadh/koanf" | |||
"github.com/knadh/koanf/parsers/json" | |||
"github.com/knadh/koanf/parsers/toml" | |||
"github.com/knadh/koanf/parsers/yaml" | |||
"github.com/knadh/koanf/providers/rawbytes" | |||
"seata.apache.org/seata-go/pkg/discovery" | |||
"seata.apache.org/seata-go/pkg/datasource/sql" | |||
"seata.apache.org/seata-go/pkg/datasource/sql/undo" | |||
remoteConfig "seata.apache.org/seata-go/pkg/remoting/config" | |||
"seata.apache.org/seata-go/pkg/rm" | |||
"seata.apache.org/seata-go/pkg/rm/tcc" | |||
"seata.apache.org/seata-go/pkg/tm" | |||
"seata.apache.org/seata-go/pkg/util/flagext" | |||
) | |||
const ( | |||
configFileEnvKey = "SEATA_GO_CONFIG_PATH" | |||
configPrefix = "seata" | |||
) | |||
const ( | |||
jsonSuffix = "json" | |||
tomlSuffix = "toml" | |||
yamlSuffix = "yaml" | |||
ymlSuffix = "yml" | |||
) | |||
type ClientConfig struct { | |||
TmConfig tm.TmConfig `yaml:"tm" json:"tm,omitempty" koanf:"tm"` | |||
RmConfig rm.Config `yaml:"rm" json:"rm,omitempty" koanf:"rm"` | |||
UndoConfig undo.Config `yaml:"undo" json:"undo,omitempty" koanf:"undo"` | |||
XaConfig sql.XAConfig `yaml:"xa" json:"xa" koanf:"xa"` | |||
} | |||
func (c *ClientConfig) RegisterFlagsWithPrefix(prefix string, f *flag.FlagSet) { | |||
c.TmConfig.RegisterFlagsWithPrefix(prefix+".tm", f) | |||
c.RmConfig.RegisterFlagsWithPrefix(prefix+".rm", f) | |||
c.UndoConfig.RegisterFlagsWithPrefix(prefix+".undo", f) | |||
c.XaConfig.RegisterFlagsWithPrefix(prefix+".xa", f) | |||
} | |||
type Config struct { | |||
Enabled bool `yaml:"enabled" json:"enabled,omitempty" koanf:"enabled"` | |||
ApplicationID string `yaml:"application-id" json:"application-id,omitempty" koanf:"application-id"` | |||
TxServiceGroup string `yaml:"tx-service-group" json:"tx-service-group,omitempty" koanf:"tx-service-group"` | |||
AccessKey string `yaml:"access-key" json:"access-key,omitempty" koanf:"access-key"` | |||
SecretKey string `yaml:"secret-key" json:"secret-key,omitempty" koanf:"secret-key"` | |||
EnableAutoDataSourceProxy bool `yaml:"enable-auto-data-source-proxy" json:"enable-auto-data-source-proxy,omitempty" koanf:"enable-auto-data-source-proxy"` | |||
DataSourceProxyMode string `yaml:"data-source-proxy-mode" json:"data-source-proxy-mode,omitempty" koanf:"data-source-proxy-mode"` | |||
AsyncWorkerConfig sql.AsyncWorkerConfig `yaml:"async" json:"async" koanf:"async"` | |||
TCCConfig tcc.Config `yaml:"tcc" json:"tcc" koanf:"tcc"` | |||
ClientConfig ClientConfig `yaml:"client" json:"client" koanf:"client"` | |||
GettyConfig remoteConfig.Config `yaml:"getty" json:"getty" koanf:"getty"` | |||
TransportConfig remoteConfig.TransportConfig `yaml:"transport" json:"transport" koanf:"transport"` | |||
ServiceConfig discovery.ServiceConfig `yaml:"service" json:"service" koanf:"service"` | |||
RegistryConfig discovery.RegistryConfig `yaml:"registry" json:"registry" koanf:"registry"` | |||
} | |||
func (c *Config) RegisterFlags(f *flag.FlagSet) { | |||
f.BoolVar(&c.Enabled, "enabled", true, "Whether enable auto configuration.") | |||
f.StringVar(&c.ApplicationID, "application-id", "seata-go", "Application id.") | |||
f.StringVar(&c.TxServiceGroup, "tx-service-group", "default_tx_group", "Transaction service group.") | |||
f.StringVar(&c.AccessKey, "access-key", "", "Used for aliyun accessKey.") | |||
f.StringVar(&c.SecretKey, "secret-key", "", "Used for aliyun secretKey.") | |||
f.BoolVar(&c.EnableAutoDataSourceProxy, "enable-auto-data-source-proxy", true, "Whether enable auto proxying of datasource bean.") | |||
f.StringVar(&c.DataSourceProxyMode, "data-source-proxy-mode", "AT", "Data source proxy mode.") | |||
c.AsyncWorkerConfig.RegisterFlagsWithPrefix("async-worker", f) | |||
c.TCCConfig.RegisterFlagsWithPrefix("tcc", f) | |||
c.ClientConfig.RegisterFlagsWithPrefix("client", f) | |||
c.GettyConfig.RegisterFlagsWithPrefix("getty", f) | |||
c.TransportConfig.RegisterFlagsWithPrefix("transport", f) | |||
c.RegistryConfig.RegisterFlagsWithPrefix("registry", f) | |||
c.ServiceConfig.RegisterFlagsWithPrefix("service", f) | |||
} | |||
type loaderConf struct { | |||
suffix string // loaderConf file extension default yaml | |||
path string // loaderConf file path default ./conf/seatago.yaml | |||
delim string // loaderConf file delim default . | |||
bytes []byte // config bytes | |||
name string // config file name | |||
} | |||
// Load parse config from user config path | |||
func LoadPath(configFilePath string) *Config { | |||
if configFilePath == "" { | |||
configFilePath = os.Getenv(configFileEnvKey) | |||
if configFilePath == "" { | |||
panic("system variable SEATA_GO_CONFIG_PATH is empty") | |||
} | |||
} | |||
var cfg Config | |||
// This sets default values from flags to the config. | |||
// It needs to be called before parsing the config file! | |||
flagext.RegisterFlags(&cfg) | |||
conf := newLoaderConf(configFilePath) | |||
koan := getConfigResolver(conf) | |||
if err := koan.UnmarshalWithConf(configPrefix, &cfg, koanf.UnmarshalConf{Tag: yamlSuffix}); err != nil { | |||
panic(err) | |||
} | |||
return &cfg | |||
} | |||
// Load parse config from json bytes | |||
func LoadJson(bytes []byte) *Config { | |||
var cfg Config | |||
// This sets default values from flags to the config. | |||
// It needs to be called before parsing the config file! | |||
flagext.RegisterFlags(&cfg) | |||
koan := getJsonConfigResolver(bytes) | |||
if err := koan.Unmarshal("", &cfg); err != nil { | |||
panic(err) | |||
} | |||
return &cfg | |||
} | |||
// getJsonConfigResolver get json config resolver | |||
func getJsonConfigResolver(bytes []byte) *koanf.Koanf { | |||
k := koanf.New(".") | |||
if err := k.Load(rawbytes.Provider(bytes), json.Parser()); err != nil { | |||
panic(err) | |||
} | |||
return k | |||
} | |||
// resolverFilePath resolver file path | |||
// eg: give a ./conf/seatago.yaml return seatago and yaml | |||
func resolverFilePath(path string) (name, suffix string) { | |||
paths := strings.Split(path, "/") | |||
fileName := strings.Split(paths[len(paths)-1], ".") | |||
if len(fileName) < 2 { | |||
return fileName[0], yamlSuffix | |||
} | |||
return fileName[0], fileName[1] | |||
} | |||
// getConfigResolver get config resolver | |||
func getConfigResolver(conf *loaderConf) *koanf.Koanf { | |||
var ( | |||
k *koanf.Koanf | |||
err error | |||
) | |||
if len(conf.suffix) <= 0 { | |||
conf.suffix = yamlSuffix | |||
} | |||
if len(conf.delim) <= 0 { | |||
conf.delim = "." | |||
} | |||
bytes := conf.bytes | |||
if len(bytes) <= 0 { | |||
panic(fmt.Errorf("bytes is nil,please set bytes or file path")) | |||
} | |||
k = koanf.New(conf.delim) | |||
switch conf.suffix { | |||
case yamlSuffix, ymlSuffix: | |||
err = k.Load(rawbytes.Provider(bytes), yaml.Parser()) | |||
case jsonSuffix: | |||
err = k.Load(rawbytes.Provider(bytes), json.Parser()) | |||
case tomlSuffix: | |||
err = k.Load(rawbytes.Provider(bytes), toml.Parser()) | |||
default: | |||
err = fmt.Errorf("no support %s file suffix", conf.suffix) | |||
} | |||
if err != nil { | |||
panic(err) | |||
} | |||
return k | |||
} | |||
func newLoaderConf(configFilePath string) *loaderConf { | |||
name, suffix := resolverFilePath(configFilePath) | |||
conf := &loaderConf{ | |||
suffix: suffix, | |||
path: absolutePath(configFilePath), | |||
delim: ".", | |||
name: name, | |||
} | |||
if len(conf.bytes) <= 0 { | |||
if bytes, err := ioutil.ReadFile(conf.path); err != nil { | |||
panic(err) | |||
} else { | |||
conf.bytes = bytes | |||
} | |||
} | |||
return conf | |||
} | |||
// absolutePath get absolut path | |||
func absolutePath(inPath string) string { | |||
if inPath == "$HOME" || strings.HasPrefix(inPath, "$HOME"+string(os.PathSeparator)) { | |||
inPath = userHomeDir() + inPath[5:] | |||
} | |||
if filepath.IsAbs(inPath) { | |||
return filepath.Clean(inPath) | |||
} | |||
p, err := filepath.Abs(inPath) | |||
if err == nil { | |||
return filepath.Clean(p) | |||
} | |||
return "" | |||
} | |||
// userHomeDir get gopath | |||
func userHomeDir() string { | |||
if runtime.GOOS == "windows" { | |||
home := os.Getenv("HOMEDRIVE") + os.Getenv("HOMEPATH") | |||
if home == "" { | |||
home = os.Getenv("USERPROFILE") | |||
} | |||
return home | |||
} | |||
return os.Getenv("HOME") | |||
} |
@@ -0,0 +1,151 @@ | |||
package config | |||
import ( | |||
"io" | |||
"io/ioutil" | |||
"os" | |||
"time" | |||
"google.golang.org/grpc/credentials" | |||
"google.golang.org/grpc/keepalive" | |||
"github.com/opentrx/seata-golang/v2/pkg/util/log" | |||
"github.com/opentrx/seata-golang/v2/pkg/util/parser" | |||
) | |||
var configuration *Configuration | |||
// Configuration client configuration | |||
type Configuration struct { | |||
Addressing string `yaml:"addressing" json:"addressing"` | |||
ServerAddressing string `yaml:"serverAddressing" json:"serverAddressing"` | |||
TMConfig TMConfig `yaml:"tm" json:"tm,omitempty"` | |||
ATConfig ATConfig `yaml:"at" json:"at,omitempty"` | |||
ClientParameters struct { | |||
Time time.Duration `yaml:"time"` | |||
Timeout time.Duration `yaml:"timeout"` | |||
PermitWithoutStream bool `yaml:"permitWithoutStream"` | |||
} `yaml:"clientParameters"` | |||
ClientTLS struct { | |||
Enable bool `yaml:"enable"` | |||
CertFilePath string `yaml:"certFilePath"` | |||
ServerName string `yaml:"serverName"` | |||
} `yaml:"clientTLS"` | |||
Log struct { | |||
LogPath string `yaml:"logPath"` | |||
LogLevel log.Level `yaml:"logLevel"` | |||
} `yaml:"log"` | |||
} | |||
// TMConfig | |||
type TMConfig struct { | |||
CommitRetryCount int32 `default:"5" yaml:"commitRetryCount" json:"commitRetryCount,omitempty"` | |||
RollbackRetryCount int32 `default:"5" yaml:"rollbackRetryCount" json:"rollbackRetryCount,omitempty"` | |||
} | |||
// ATConfig | |||
type ATConfig struct { | |||
DSN string `yaml:"dsn" json:"dsn,omitempty"` | |||
ReportRetryCount int `default:"5" yaml:"reportRetryCount" json:"reportRetryCount,omitempty"` | |||
ReportSuccessEnable bool `default:"false" yaml:"reportSuccessEnable" json:"reportSuccessEnable,omitempty"` | |||
LockRetryInterval time.Duration `default:"10ms" yaml:"lockRetryInterval" json:"lockRetryInterval,omitempty"` | |||
LockRetryTimes int `default:"30" yaml:"lockRetryTimes" json:"lockRetryTimes,omitempty"` | |||
} | |||
// GetTMConfig return TMConfig | |||
func GetTMConfig() TMConfig { | |||
return configuration.TMConfig | |||
} | |||
// GetATConfig return ATConfig | |||
func GetATConfig() ATConfig { | |||
return configuration.ATConfig | |||
} | |||
// GetClientParameters used to config grpc connection keep alive | |||
func GetClientParameters() keepalive.ClientParameters { | |||
return configuration.GetClientParameters() | |||
} | |||
// GetClientParameters used to config grpc connection keep alive | |||
func (configuration *Configuration) GetClientParameters() keepalive.ClientParameters { | |||
cp := keepalive.ClientParameters{ | |||
Time: 10 * time.Second, | |||
Timeout: time.Second, | |||
PermitWithoutStream: true, | |||
} | |||
if configuration.ClientParameters.Time > 0 { | |||
cp.Time = configuration.ClientParameters.Timeout | |||
} | |||
if configuration.ClientParameters.Timeout > 0 { | |||
cp.Timeout = configuration.ClientParameters.Timeout | |||
} | |||
cp.PermitWithoutStream = configuration.ClientParameters.PermitWithoutStream | |||
return cp | |||
} | |||
func (configuration *Configuration) GetClientTLS() credentials.TransportCredentials { | |||
if !configuration.ClientTLS.Enable { | |||
return nil | |||
} | |||
cred, err := credentials.NewClientTLSFromFile(configuration.ClientTLS.CertFilePath, configuration.ClientTLS.ServerName) | |||
if err != nil { | |||
log.Fatalf("%v using TLS failed", err) | |||
} | |||
return cred | |||
} | |||
// Parse parses an input configuration yaml document into a Configuration struct | |||
// | |||
// Environment variables may be used to override configuration parameters other than version, | |||
// following the scheme below: | |||
// Configuration.Abc may be replaced by the value of SEATA_ABC, | |||
// Configuration.Abc.Xyz may be replaced by the value of SEATA_ABC_XYZ, and so forth | |||
func parse(rd io.Reader) (*Configuration, error) { | |||
in, err := ioutil.ReadAll(rd) | |||
if err != nil { | |||
return nil, err | |||
} | |||
p := parser.NewParser("seata") | |||
config := new(Configuration) | |||
err = p.Parse(in, config) | |||
if err != nil { | |||
return nil, err | |||
} | |||
return config, nil | |||
} | |||
// InitConfiguration init configuration from a file path | |||
func InitConfiguration(configurationPath string) *Configuration { | |||
fp, err := os.Open(configurationPath) | |||
if err != nil { | |||
log.Fatalf("open configuration file fail, %v", err) | |||
} | |||
config, err := parse(fp) | |||
if err != nil { | |||
log.Fatalf("error parsing %s: %v", configurationPath, err) | |||
} | |||
defer func() { | |||
err = fp.Close() | |||
if err != nil { | |||
log.Error(err) | |||
} | |||
}() | |||
configuration = config | |||
return configuration | |||
} | |||
func SetConfiguration(config *Configuration) { | |||
configuration = config | |||
} |
@@ -1,226 +0,0 @@ | |||
/* | |||
* Licensed to the Apache Software Foundation (ASF) under one or more | |||
* contributor license agreements. See the NOTICE file distributed with | |||
* this work for additional information regarding copyright ownership. | |||
* The ASF licenses this file to You under the Apache License, Version 2.0 | |||
* (the "License"); you may not use this file except in compliance with | |||
* the License. You may obtain a copy of the License at | |||
* | |||
* http://www.apache.org/licenses/LICENSE-2.0 | |||
* | |||
* Unless required by applicable law or agreed to in writing, software | |||
* distributed under the License is distributed on an "AS IS" BASIS, | |||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
* See the License for the specific language governing permissions and | |||
* limitations under the License. | |||
*/ | |||
package client | |||
import ( | |||
"flag" | |||
"os" | |||
"testing" | |||
"time" | |||
"github.com/stretchr/testify/assert" | |||
) | |||
func TestLoadPath(t *testing.T) { | |||
cfg := LoadPath("../../testdata/conf/seatago.yml") | |||
assert.NotNil(t, cfg) | |||
assert.Equal(t, true, cfg.Enabled) | |||
assert.Equal(t, "applicationName", cfg.ApplicationID) | |||
assert.Equal(t, "default_tx_group", cfg.TxServiceGroup) | |||
assert.Equal(t, "aliyunAccessKey", cfg.AccessKey) | |||
assert.Equal(t, "aliyunSecretKey", cfg.SecretKey) | |||
assert.Equal(t, true, cfg.EnableAutoDataSourceProxy) | |||
assert.Equal(t, "AT", cfg.DataSourceProxyMode) | |||
assert.NotNil(t, cfg.TCCConfig) | |||
assert.NotNil(t, cfg.TCCConfig.FenceConfig) | |||
assert.Equal(t, false, cfg.TCCConfig.FenceConfig.Enable) | |||
assert.Equal(t, "root:12345678@tcp(127.0.0.1:3306)/seata_client1?charset=utf8&parseTime=True", cfg.TCCConfig.FenceConfig.Url) | |||
assert.Equal(t, "tcc_fence_log_test", cfg.TCCConfig.FenceConfig.LogTableName) | |||
assert.Equal(t, time.Second*60, cfg.TCCConfig.FenceConfig.CleanPeriod) | |||
assert.NotNil(t, cfg.ClientConfig) | |||
assert.NotNil(t, cfg.ClientConfig.TmConfig) | |||
assert.Equal(t, 5, cfg.ClientConfig.TmConfig.CommitRetryCount) | |||
assert.Equal(t, 5, cfg.ClientConfig.TmConfig.RollbackRetryCount) | |||
assert.Equal(t, time.Second*60, cfg.ClientConfig.TmConfig.DefaultGlobalTransactionTimeout) | |||
assert.Equal(t, false, cfg.ClientConfig.TmConfig.DegradeCheck) | |||
assert.Equal(t, 2000, cfg.ClientConfig.TmConfig.DegradeCheckPeriod) | |||
assert.Equal(t, time.Second*10, cfg.ClientConfig.TmConfig.DegradeCheckAllowTimes) | |||
assert.Equal(t, -2147482648, cfg.ClientConfig.TmConfig.InterceptorOrder) | |||
assert.Equal(t, 10000, cfg.ClientConfig.RmConfig.AsyncCommitBufferLimit) | |||
assert.Equal(t, 5, cfg.ClientConfig.RmConfig.ReportRetryCount) | |||
assert.Equal(t, false, cfg.ClientConfig.RmConfig.TableMetaCheckEnable) | |||
assert.Equal(t, false, cfg.ClientConfig.RmConfig.ReportSuccessEnable) | |||
assert.Equal(t, false, cfg.ClientConfig.RmConfig.SagaBranchRegisterEnable) | |||
assert.Equal(t, "fastjson", cfg.ClientConfig.RmConfig.SagaJsonParser) | |||
assert.Equal(t, false, cfg.ClientConfig.RmConfig.SagaCompensatePersistModeUpdate) | |||
assert.Equal(t, false, cfg.ClientConfig.RmConfig.SagaRetryPersistModeUpdate) | |||
assert.Equal(t, -2147482648, cfg.ClientConfig.RmConfig.TccActionInterceptorOrder) | |||
assert.Equal(t, "druid", cfg.ClientConfig.RmConfig.SqlParserType) | |||
assert.Equal(t, 30*time.Second, cfg.ClientConfig.RmConfig.LockConfig.RetryInterval) | |||
assert.Equal(t, 10, cfg.ClientConfig.RmConfig.LockConfig.RetryTimes) | |||
assert.Equal(t, true, cfg.ClientConfig.RmConfig.LockConfig.RetryPolicyBranchRollbackOnConflict) | |||
assert.NotNil(t, cfg.ClientConfig.UndoConfig) | |||
assert.Equal(t, true, cfg.ClientConfig.UndoConfig.DataValidation) | |||
assert.Equal(t, "json", cfg.ClientConfig.UndoConfig.LogSerialization) | |||
assert.Equal(t, "undo_log", cfg.ClientConfig.UndoConfig.LogTable) | |||
assert.Equal(t, true, cfg.ClientConfig.UndoConfig.OnlyCareUpdateColumns) | |||
assert.NotNil(t, cfg.ClientConfig.UndoConfig.CompressConfig) | |||
assert.Equal(t, true, cfg.ClientConfig.UndoConfig.CompressConfig.Enable) | |||
assert.Equal(t, "zip", cfg.ClientConfig.UndoConfig.CompressConfig.Type) | |||
assert.Equal(t, "64k", cfg.ClientConfig.UndoConfig.CompressConfig.Threshold) | |||
assert.NotNil(t, cfg.GettyConfig) | |||
assert.NotNil(t, cfg.GettyConfig.SessionConfig) | |||
assert.Equal(t, 0, cfg.GettyConfig.ReconnectInterval) | |||
assert.Equal(t, 1, cfg.GettyConfig.ConnectionNum) | |||
assert.Equal(t, false, cfg.GettyConfig.SessionConfig.CompressEncoding) | |||
assert.Equal(t, true, cfg.GettyConfig.SessionConfig.TCPNoDelay) | |||
assert.Equal(t, true, cfg.GettyConfig.SessionConfig.TCPKeepAlive) | |||
assert.Equal(t, time.Minute*2, cfg.GettyConfig.SessionConfig.KeepAlivePeriod) | |||
assert.Equal(t, 262144, cfg.GettyConfig.SessionConfig.TCPRBufSize) | |||
assert.Equal(t, 65536, cfg.GettyConfig.SessionConfig.TCPWBufSize) | |||
assert.Equal(t, time.Second, cfg.GettyConfig.SessionConfig.TCPReadTimeout) | |||
assert.Equal(t, time.Second*5, cfg.GettyConfig.SessionConfig.TCPWriteTimeout) | |||
assert.Equal(t, time.Second, cfg.GettyConfig.SessionConfig.WaitTimeout) | |||
assert.Equal(t, 16498688, cfg.GettyConfig.SessionConfig.MaxMsgLen) | |||
assert.Equal(t, "client_test", cfg.GettyConfig.SessionConfig.SessionName) | |||
assert.Equal(t, time.Second, cfg.GettyConfig.SessionConfig.CronPeriod) | |||
assert.NotNil(t, cfg.TransportConfig) | |||
assert.NotNil(t, cfg.TransportConfig.ShutdownConfig) | |||
assert.Equal(t, time.Second*3, cfg.TransportConfig.ShutdownConfig.Wait) | |||
assert.Equal(t, "TCP", cfg.TransportConfig.Type) | |||
assert.Equal(t, "NIO", cfg.TransportConfig.Server) | |||
assert.Equal(t, true, cfg.TransportConfig.Heartbeat) | |||
assert.Equal(t, "seata", cfg.TransportConfig.Serialization) | |||
assert.Equal(t, "none", cfg.TransportConfig.Compressor) | |||
assert.Equal(t, false, cfg.TransportConfig.EnableTmClientBatchSendRequest) | |||
assert.Equal(t, true, cfg.TransportConfig.EnableRmClientBatchSendRequest) | |||
assert.Equal(t, time.Second*30, cfg.TransportConfig.RPCRmRequestTimeout) | |||
assert.Equal(t, time.Second*30, cfg.TransportConfig.RPCTmRequestTimeout) | |||
assert.NotNil(t, cfg.ServiceConfig) | |||
assert.Equal(t, false, cfg.ServiceConfig.EnableDegrade) | |||
assert.Equal(t, false, cfg.ServiceConfig.DisableGlobalTransaction) | |||
assert.Equal(t, "default", cfg.ServiceConfig.VgroupMapping["default_tx_group"]) | |||
assert.Equal(t, "127.0.0.1:8091", cfg.ServiceConfig.Grouplist["default"]) | |||
assert.NotNil(t, cfg.RegistryConfig) | |||
assert.Equal(t, "file", cfg.RegistryConfig.Type) | |||
assert.Equal(t, "seatago.yml", cfg.RegistryConfig.File.Name) | |||
assert.Equal(t, "seata-server", cfg.RegistryConfig.Nacos.Application) | |||
assert.Equal(t, "127.0.0.1:8848", cfg.RegistryConfig.Nacos.ServerAddr) | |||
assert.Equal(t, "SEATA_GROUP", cfg.RegistryConfig.Nacos.Group) | |||
assert.Equal(t, "test-namespace", cfg.RegistryConfig.Nacos.Namespace) | |||
assert.Equal(t, "test-username", cfg.RegistryConfig.Nacos.Username) | |||
assert.Equal(t, "test-password", cfg.RegistryConfig.Nacos.Password) | |||
assert.Equal(t, "test-access-key", cfg.RegistryConfig.Nacos.AccessKey) | |||
assert.Equal(t, "test-secret-key", cfg.RegistryConfig.Nacos.SecretKey) | |||
assert.Equal(t, "default", cfg.RegistryConfig.Etcd3.Cluster) | |||
assert.Equal(t, "http://localhost:2379", cfg.RegistryConfig.Etcd3.ServerAddr) | |||
// reset flag.CommandLine | |||
flag.CommandLine = flag.NewFlagSet(os.Args[0], flag.ExitOnError) | |||
} | |||
func TestLoadJson(t *testing.T) { | |||
confJson := `{"enabled":false,"application-id":"application_test","tx-service-group":"default_tx_group","access-key":"test","secret-key":"test","enable-auto-data-source-proxy":false,"data-source-proxy-mode":"AT","client":{"rm":{"async-commit-buffer-limit":10000,"report-retry-count":5,"table-meta-check-enable":false,"report-success-enable":false,"saga-branch-register-enable":false,"saga-json-parser":"fastjson","saga-retry-persist-mode-update":false,"saga-compensate-persist-mode-update":false,"tcc-action-interceptor-order":-2147482648,"sql-parser-type":"druid","lock":{"retry-interval":"30s","retry-times":10,"retry-policy-branch-rollback-on-conflict":true}},"tm":{"commit-retry-count":5,"rollback-retry-count":5,"default-global-transaction-timeout":"60s","degrade-check":false,"degrade-check-period":2000,"degrade-check-allow-times":"10s","interceptor-order":-2147482648},"undo":{"data-validation":false,"log-serialization":"jackson222","only-care-update-columns":false,"log-table":"undo_log333","compress":{"enable":false,"type":"zip111","threshold":"128k"}}},"tcc":{"fence":{"enable":false,"url":"root:12345678@tcp(127.0.0.1:3306)/seata_client1?charset=utf8&parseTime=True","log-table-name":"tcc_fence_log_test2","clean-period":80000000000}},"getty":{"reconnect-interval":1,"connection-num":10,"session":{"compress-encoding":true,"tcp-no-delay":false,"tcp-keep-alive":false,"keep-alive-period":"120s","tcp-r-buf-size":261120,"tcp-w-buf-size":32768,"tcp-read-timeout":"2s","tcp-write-timeout":"8s","wait-timeout":"2s","max-msg-len":261120,"session-name":"client_test","cron-period":"2s"}},"transport":{"shutdown":{"wait":"3s"},"type":"TCP","server":"NIO","heartbeat":true,"serialization":"seata","compressor":"none"," enable-tm-client-batch-send-request":false,"enable-rm-client-batch-send-request":true,"rpc-rm-request-timeout":"30s","rpc-tm-request-timeout":"30s"},"service":{"enable-degrade":true,"disable-global-transaction":true,"vgroup-mapping":{"default_tx_group":"default_test"},"grouplist":{"default":"127.0.0.1:8092"}}}` | |||
cfg := LoadJson([]byte(confJson)) | |||
assert.NotNil(t, cfg) | |||
assert.Equal(t, false, cfg.Enabled) | |||
assert.Equal(t, "application_test", cfg.ApplicationID) | |||
assert.Equal(t, "default_tx_group", cfg.TxServiceGroup) | |||
assert.Equal(t, "test", cfg.AccessKey) | |||
assert.Equal(t, "test", cfg.SecretKey) | |||
assert.Equal(t, false, cfg.EnableAutoDataSourceProxy) | |||
assert.Equal(t, "AT", cfg.DataSourceProxyMode) | |||
assert.Equal(t, 10000, cfg.ClientConfig.RmConfig.AsyncCommitBufferLimit) | |||
assert.Equal(t, 5, cfg.ClientConfig.RmConfig.ReportRetryCount) | |||
assert.Equal(t, false, cfg.ClientConfig.RmConfig.TableMetaCheckEnable) | |||
assert.Equal(t, false, cfg.ClientConfig.RmConfig.ReportSuccessEnable) | |||
assert.Equal(t, false, cfg.ClientConfig.RmConfig.SagaBranchRegisterEnable) | |||
assert.Equal(t, "fastjson", cfg.ClientConfig.RmConfig.SagaJsonParser) | |||
assert.Equal(t, false, cfg.ClientConfig.RmConfig.SagaCompensatePersistModeUpdate) | |||
assert.Equal(t, false, cfg.ClientConfig.RmConfig.SagaRetryPersistModeUpdate) | |||
assert.Equal(t, -2147482648, cfg.ClientConfig.RmConfig.TccActionInterceptorOrder) | |||
assert.Equal(t, "druid", cfg.ClientConfig.RmConfig.SqlParserType) | |||
assert.Equal(t, 30*time.Second, cfg.ClientConfig.RmConfig.LockConfig.RetryInterval) | |||
assert.Equal(t, 10, cfg.ClientConfig.RmConfig.LockConfig.RetryTimes) | |||
assert.Equal(t, true, cfg.ClientConfig.RmConfig.LockConfig.RetryPolicyBranchRollbackOnConflict) | |||
assert.NotNil(t, cfg.ClientConfig.UndoConfig) | |||
assert.Equal(t, false, cfg.ClientConfig.UndoConfig.DataValidation) | |||
assert.Equal(t, "jackson222", cfg.ClientConfig.UndoConfig.LogSerialization) | |||
assert.Equal(t, "undo_log333", cfg.ClientConfig.UndoConfig.LogTable) | |||
assert.Equal(t, false, cfg.ClientConfig.UndoConfig.OnlyCareUpdateColumns) | |||
assert.NotNil(t, cfg.ClientConfig.UndoConfig.CompressConfig) | |||
assert.Equal(t, false, cfg.ClientConfig.UndoConfig.CompressConfig.Enable) | |||
assert.Equal(t, "zip111", cfg.ClientConfig.UndoConfig.CompressConfig.Type) | |||
assert.Equal(t, "128k", cfg.ClientConfig.UndoConfig.CompressConfig.Threshold) | |||
assert.NotNil(t, cfg.TCCConfig) | |||
assert.NotNil(t, cfg.TCCConfig.FenceConfig) | |||
assert.Equal(t, false, cfg.TCCConfig.FenceConfig.Enable) | |||
assert.Equal(t, "root:12345678@tcp(127.0.0.1:3306)/seata_client1?charset=utf8&parseTime=True", cfg.TCCConfig.FenceConfig.Url) | |||
assert.Equal(t, "tcc_fence_log_test2", cfg.TCCConfig.FenceConfig.LogTableName) | |||
assert.Equal(t, time.Second*80, cfg.TCCConfig.FenceConfig.CleanPeriod) | |||
assert.NotNil(t, cfg.ClientConfig) | |||
assert.NotNil(t, cfg.ClientConfig.TmConfig) | |||
assert.Equal(t, 5, cfg.ClientConfig.TmConfig.CommitRetryCount) | |||
assert.Equal(t, 5, cfg.ClientConfig.TmConfig.RollbackRetryCount) | |||
assert.Equal(t, time.Second*60, cfg.ClientConfig.TmConfig.DefaultGlobalTransactionTimeout) | |||
assert.Equal(t, false, cfg.ClientConfig.TmConfig.DegradeCheck) | |||
assert.Equal(t, 2000, cfg.ClientConfig.TmConfig.DegradeCheckPeriod) | |||
assert.Equal(t, time.Second*10, cfg.ClientConfig.TmConfig.DegradeCheckAllowTimes) | |||
assert.Equal(t, -2147482648, cfg.ClientConfig.TmConfig.InterceptorOrder) | |||
assert.NotNil(t, cfg.GettyConfig) | |||
assert.NotNil(t, cfg.GettyConfig.SessionConfig) | |||
assert.Equal(t, 1, cfg.GettyConfig.ReconnectInterval) | |||
assert.Equal(t, 10, cfg.GettyConfig.ConnectionNum) | |||
assert.Equal(t, true, cfg.GettyConfig.SessionConfig.CompressEncoding) | |||
assert.Equal(t, false, cfg.GettyConfig.SessionConfig.TCPNoDelay) | |||
assert.Equal(t, false, cfg.GettyConfig.SessionConfig.TCPKeepAlive) | |||
assert.Equal(t, time.Minute*2, cfg.GettyConfig.SessionConfig.KeepAlivePeriod) | |||
assert.Equal(t, 261120, cfg.GettyConfig.SessionConfig.TCPRBufSize) | |||
assert.Equal(t, 32768, cfg.GettyConfig.SessionConfig.TCPWBufSize) | |||
assert.Equal(t, time.Second*2, cfg.GettyConfig.SessionConfig.TCPReadTimeout) | |||
assert.Equal(t, time.Second*8, cfg.GettyConfig.SessionConfig.TCPWriteTimeout) | |||
assert.Equal(t, time.Second*2, cfg.GettyConfig.SessionConfig.WaitTimeout) | |||
assert.Equal(t, 261120, cfg.GettyConfig.SessionConfig.MaxMsgLen) | |||
assert.Equal(t, "client_test", cfg.GettyConfig.SessionConfig.SessionName) | |||
assert.Equal(t, time.Second*2, cfg.GettyConfig.SessionConfig.CronPeriod) | |||
assert.NotNil(t, cfg.TransportConfig) | |||
assert.NotNil(t, cfg.TransportConfig.ShutdownConfig) | |||
assert.Equal(t, time.Second*3, cfg.TransportConfig.ShutdownConfig.Wait) | |||
assert.Equal(t, "TCP", cfg.TransportConfig.Type) | |||
assert.Equal(t, "NIO", cfg.TransportConfig.Server) | |||
assert.Equal(t, true, cfg.TransportConfig.Heartbeat) | |||
assert.Equal(t, "seata", cfg.TransportConfig.Serialization) | |||
assert.Equal(t, "none", cfg.TransportConfig.Compressor) | |||
assert.Equal(t, false, cfg.TransportConfig.EnableTmClientBatchSendRequest) | |||
assert.Equal(t, true, cfg.TransportConfig.EnableRmClientBatchSendRequest) | |||
assert.Equal(t, time.Second*30, cfg.TransportConfig.RPCRmRequestTimeout) | |||
assert.Equal(t, time.Second*30, cfg.TransportConfig.RPCTmRequestTimeout) | |||
assert.NotNil(t, cfg.ServiceConfig) | |||
assert.Equal(t, true, cfg.ServiceConfig.EnableDegrade) | |||
assert.Equal(t, true, cfg.ServiceConfig.DisableGlobalTransaction) | |||
assert.Equal(t, "default_test", cfg.ServiceConfig.VgroupMapping["default_tx_group"]) | |||
assert.Equal(t, "127.0.0.1:8092", cfg.ServiceConfig.Grouplist["default"]) | |||
// reset flag.CommandLine | |||
flag.CommandLine = flag.NewFlagSet(os.Args[0], flag.ExitOnError) | |||
} |
@@ -0,0 +1,169 @@ | |||
package proxy | |||
import ( | |||
"context" | |||
"reflect" | |||
"sync" | |||
"unicode" | |||
"unicode/utf8" | |||
ctx "github.com/opentrx/seata-golang/v2/pkg/client/base/context" | |||
"github.com/opentrx/seata-golang/v2/pkg/util/log" | |||
) | |||
var ( | |||
// serviceDescriptorMap, string -> *ServiceDescriptor | |||
serviceDescriptorMap = sync.Map{} | |||
) | |||
// MethodDescriptor | |||
type MethodDescriptor struct { | |||
Method reflect.Method | |||
CallerValue reflect.Value | |||
CtxType reflect.Type | |||
ArgsType []reflect.Type | |||
ArgsNum int | |||
ReturnValuesType []reflect.Type | |||
ReturnValuesNum int | |||
} | |||
// ServiceDescriptor | |||
type ServiceDescriptor struct { | |||
Name string | |||
ReflectType reflect.Type | |||
ReflectValue reflect.Value | |||
Methods sync.Map // string -> *MethodDescriptor | |||
} | |||
// Register | |||
func Register(service interface{}, methodName string) *MethodDescriptor { | |||
serviceType := reflect.TypeOf(service) | |||
serviceValue := reflect.ValueOf(service) | |||
svcName := reflect.Indirect(serviceValue).Type().Name() | |||
svcDesc, _ := serviceDescriptorMap.LoadOrStore(svcName, &ServiceDescriptor{ | |||
Name: svcName, | |||
ReflectType: serviceType, | |||
ReflectValue: serviceValue, | |||
Methods: sync.Map{}, | |||
}) | |||
svcDescriptor := svcDesc.(*ServiceDescriptor) | |||
methodDesc, methodExist := svcDescriptor.Methods.Load(methodName) | |||
if methodExist { | |||
methodDescriptor := methodDesc.(*MethodDescriptor) | |||
return methodDescriptor | |||
} | |||
method, methodFounded := serviceType.MethodByName(methodName) | |||
if methodFounded { | |||
methodDescriptor := describeMethod(method) | |||
if methodDescriptor != nil { | |||
methodDescriptor.CallerValue = serviceValue | |||
svcDescriptor.Methods.Store(methodName, methodDescriptor) | |||
return methodDescriptor | |||
} | |||
} | |||
return nil | |||
} | |||
// describeMethod | |||
// might return nil when method is not exported or some other error | |||
func describeMethod(method reflect.Method) *MethodDescriptor { | |||
methodType := method.Type | |||
methodName := method.Name | |||
inNum := methodType.NumIn() | |||
outNum := methodType.NumOut() | |||
// Method must be exported. | |||
if method.PkgPath != "" { | |||
return nil | |||
} | |||
var ( | |||
ctxType reflect.Type | |||
argsType, returnValuesType []reflect.Type | |||
) | |||
for index := 1; index < inNum; index++ { | |||
if methodType.In(index).String() == "context.Context" { | |||
ctxType = methodType.In(index) | |||
} | |||
argsType = append(argsType, methodType.In(index)) | |||
// need not be a pointer. | |||
if !isExportedOrBuiltinType(methodType.In(index)) { | |||
log.Errorf("argument type of method %q is not exported %v", methodName, methodType.In(index)) | |||
return nil | |||
} | |||
} | |||
// returnValuesType | |||
for num := 0; num < outNum; num++ { | |||
returnValuesType = append(returnValuesType, methodType.Out(num)) | |||
} | |||
return &MethodDescriptor{ | |||
Method: method, | |||
CtxType: ctxType, | |||
ArgsType: argsType, | |||
ArgsNum: inNum, | |||
ReturnValuesType: returnValuesType, | |||
ReturnValuesNum: outNum, | |||
} | |||
} | |||
// Is this an exported - upper case - name | |||
func isExported(name string) bool { | |||
s, _ := utf8.DecodeRuneInString(name) | |||
return unicode.IsUpper(s) | |||
} | |||
// Is this type exported or a builtin? | |||
func isExportedOrBuiltinType(t reflect.Type) bool { | |||
for t.Kind() == reflect.Ptr { | |||
t = t.Elem() | |||
} | |||
// PkgPath will be non-empty even for an exported type, | |||
// so we need to check the type name as well. | |||
return isExported(t.Name()) || t.PkgPath() == "" | |||
} | |||
// Invoke | |||
func Invoke(methodDesc *MethodDescriptor, ctx *ctx.RootContext, args []interface{}) []reflect.Value { | |||
in := []reflect.Value{methodDesc.CallerValue} | |||
for i := 0; i < len(args); i++ { | |||
t := reflect.ValueOf(args[i]) | |||
if methodDesc.ArgsType[i].String() == "context.Context" { | |||
t = SuiteContext(ctx, methodDesc) | |||
} | |||
if !t.IsValid() { | |||
at := methodDesc.ArgsType[i] | |||
if at.Kind() == reflect.Ptr { | |||
at = at.Elem() | |||
} | |||
t = reflect.New(at) | |||
} | |||
in = append(in, t) | |||
} | |||
returnValues := methodDesc.Method.Func.Call(in) | |||
return returnValues | |||
} | |||
func SuiteContext(ctx context.Context, methodDesc *MethodDescriptor) reflect.Value { | |||
if contextValue := reflect.ValueOf(ctx); contextValue.IsValid() { | |||
return contextValue | |||
} | |||
return reflect.Zero(methodDesc.CtxType) | |||
} | |||
func ReturnWithError(methodDesc *MethodDescriptor, err error) []reflect.Value { | |||
var result = make([]reflect.Value, 0) | |||
for i := 0; i < methodDesc.ReturnValuesNum-1; i++ { | |||
result = append(result, reflect.Zero(methodDesc.ReturnValuesType[i])) | |||
} | |||
result = append(result, reflect.ValueOf(err)) | |||
return result | |||
} |
@@ -0,0 +1,221 @@ | |||
package proxy | |||
import ( | |||
"context" | |||
"reflect" | |||
"testing" | |||
"github.com/opentrx/seata-golang/v2/pkg/client/base/model" | |||
"github.com/pkg/errors" | |||
"github.com/stretchr/testify/assert" | |||
) | |||
type Svc struct{} | |||
var service = &Svc{} | |||
type ProxyService struct { | |||
*Svc | |||
CreateSo func(ctx context.Context, rollback bool) error | |||
} | |||
var methodTransactionInfo = make(map[string]*model.TransactionInfo) | |||
func (svc *ProxyService) GetMethodTransactionInfo(methodName string) *model.TransactionInfo { | |||
return methodTransactionInfo[methodName] | |||
} | |||
func (svc *ProxyService) GetProxyService() interface{} { | |||
return svc.Svc | |||
} | |||
func (svc *Svc) CreateSo(ctx context.Context, rollback bool) error { | |||
return nil | |||
} | |||
var ProxySvc = &ProxyService{ | |||
Svc: service, | |||
} | |||
func TestRegister(t *testing.T) { | |||
ps := ProxySvc.GetProxyService() | |||
method, _ := reflect.TypeOf(ps).MethodByName("CreateSo") | |||
tests := []struct { | |||
name string | |||
service interface{} | |||
methodName string | |||
expectedResult *MethodDescriptor | |||
}{ | |||
{ | |||
name: "test register", | |||
service: ps, | |||
methodName: "CreateSo", | |||
expectedResult: &MethodDescriptor{ | |||
ArgsNum: 3, | |||
Method: reflect.Method{Name: "CreateSo"}, | |||
ReturnValuesNum: 1, | |||
ReturnValuesType: []reflect.Type{ | |||
method.Type.Out(0), | |||
}, | |||
ArgsType: []reflect.Type{ | |||
method.Type.In(1), | |||
method.Type.In(2), | |||
}, | |||
CtxType: method.Type.In(1), | |||
CallerValue: reflect.ValueOf(ps), | |||
}, | |||
}, | |||
} | |||
for _, tt := range tests { | |||
t.Run(tt.name, func(t *testing.T) { | |||
actualResult := Register(tt.service, tt.methodName) | |||
assert.Equal(t, tt.expectedResult.ArgsNum, actualResult.ArgsNum) | |||
assert.Equal(t, tt.expectedResult.Method.Name, actualResult.Method.Name) | |||
assert.Equal(t, tt.expectedResult.ReturnValuesNum, actualResult.ReturnValuesNum) | |||
assert.Equal(t, tt.expectedResult.ReturnValuesType, actualResult.ReturnValuesType) | |||
}) | |||
} | |||
} | |||
func TestSuiteContext(t *testing.T) { | |||
type key string | |||
const aa key = "aa" | |||
const bb key = "bb" | |||
emptyContext := context.TODO() | |||
validContext := context.WithValue(context.TODO(), aa, bb) | |||
tests := []struct { | |||
name string | |||
methodDesc *MethodDescriptor | |||
ctx context.Context | |||
expectedResult reflect.Value | |||
}{ | |||
{ | |||
name: "test suite valid context", | |||
methodDesc: &MethodDescriptor{}, | |||
ctx: emptyContext, | |||
expectedResult: reflect.ValueOf(emptyContext), | |||
}, | |||
{ | |||
name: "test suite invalid context", | |||
methodDesc: &MethodDescriptor{ | |||
CtxType: reflect.TypeOf(validContext), | |||
}, | |||
ctx: nil, | |||
expectedResult: reflect.Zero(reflect.TypeOf(validContext)), | |||
}, | |||
} | |||
for _, tt := range tests { | |||
t.Run(tt.name, func(t *testing.T) { | |||
actualResult := SuiteContext(tt.ctx, tt.methodDesc) | |||
assert.Equal(t, tt.expectedResult, actualResult) | |||
}) | |||
} | |||
} | |||
func TestReturnWithError(t *testing.T) { | |||
testingErr := errors.New("testing err") | |||
tests := []struct { | |||
name string | |||
methodDesc *MethodDescriptor | |||
err error | |||
expectedResult []reflect.Value | |||
}{ | |||
{ | |||
name: "test return with error when methodDesc.ReturnValuesNum is 2", | |||
methodDesc: &MethodDescriptor{ | |||
ReturnValuesNum: 2, | |||
ReturnValuesType: []reflect.Type{ | |||
reflect.TypeOf("1"), | |||
reflect.TypeOf(testingErr), | |||
}, | |||
}, | |||
err: testingErr, | |||
expectedResult: []reflect.Value{ | |||
reflect.Zero(reflect.TypeOf("1")), | |||
reflect.ValueOf(testingErr), | |||
}, | |||
}, | |||
{ | |||
name: "test return with error when methodDesc.ReturnValuesNum is 1", | |||
methodDesc: &MethodDescriptor{ | |||
ReturnValuesNum: 1, | |||
ReturnValuesType: []reflect.Type{ | |||
reflect.TypeOf(testingErr), | |||
}, | |||
}, | |||
err: testingErr, | |||
expectedResult: []reflect.Value{ | |||
reflect.ValueOf(testingErr), | |||
}, | |||
}, | |||
{ | |||
name: "test return with error when methodDesc.ReturnValuesNum is 0", | |||
methodDesc: &MethodDescriptor{ | |||
ReturnValuesNum: 0, | |||
ReturnValuesType: []reflect.Type{}, | |||
}, | |||
err: testingErr, | |||
expectedResult: []reflect.Value{ | |||
reflect.ValueOf(testingErr), | |||
}, | |||
}, | |||
} | |||
for _, tt := range tests { | |||
t.Run(tt.name, func(t *testing.T) { | |||
actualResult := ReturnWithError(tt.methodDesc, tt.err) | |||
for idx := range tt.expectedResult { | |||
assert.Equal(t, tt.expectedResult[idx].Type(), actualResult[idx].Type()) | |||
} | |||
}) | |||
} | |||
} | |||
func TestIsExportedOrBuiltinType(t *testing.T) { | |||
type ExportedStruct struct { | |||
Abb string | |||
} | |||
type notExportedStruct struct { | |||
Cdd string | |||
} | |||
tests := []struct { | |||
name string | |||
typeOf reflect.Type | |||
expectedResult bool | |||
}{ | |||
{ | |||
name: "test type is exported and not builtin", | |||
typeOf: reflect.TypeOf(ExportedStruct{ | |||
Abb: "testing", | |||
}), | |||
expectedResult: true, | |||
}, | |||
{ | |||
name: "test type is not exported and not builtin", | |||
typeOf: reflect.TypeOf(notExportedStruct{ | |||
Cdd: "testing", | |||
}), | |||
expectedResult: false, | |||
}, | |||
{ | |||
name: "test type is builtin", | |||
typeOf: reflect.TypeOf("Abb"), // string type | |||
expectedResult: true, | |||
}, | |||
} | |||
for _, tt := range tests { | |||
t.Run(tt.name, func(t *testing.T) { | |||
actualResult := isExportedOrBuiltinType(tt.typeOf) | |||
assert.Equal(t, tt.expectedResult, actualResult) | |||
}) | |||
} | |||
} |
@@ -0,0 +1,257 @@ | |||
package rm | |||
import ( | |||
"context" | |||
"fmt" | |||
"io" | |||
"time" | |||
"github.com/gogo/protobuf/types" | |||
"github.com/opentrx/seata-golang/v2/pkg/apis" | |||
"github.com/opentrx/seata-golang/v2/pkg/client/base/exception" | |||
"github.com/opentrx/seata-golang/v2/pkg/client/base/model" | |||
"github.com/opentrx/seata-golang/v2/pkg/util/log" | |||
"github.com/opentrx/seata-golang/v2/pkg/util/runtime" | |||
"google.golang.org/grpc/metadata" | |||
) | |||
var defaultResourceManager *ResourceManager | |||
type ResourceManagerOutbound interface { | |||
// BranchRegister register branch transaction. | |||
BranchRegister(ctx context.Context, xid string, resourceID string, branchType apis.BranchSession_BranchType, | |||
applicationData []byte, lockKeys string) (int64, error) | |||
// BranchReport report branch transaction status. | |||
BranchReport(ctx context.Context, xid string, branchID int64, branchType apis.BranchSession_BranchType, | |||
status apis.BranchSession_BranchStatus, applicationData []byte) error | |||
// LockQuery lock resource by lockKeys. | |||
LockQuery(ctx context.Context, xid string, resourceID string, branchType apis.BranchSession_BranchType, lockKeys string) (bool, error) | |||
} | |||
type ResourceManagerInterface interface { | |||
BranchCommit(ctx context.Context, request *apis.BranchCommitRequest) (*apis.BranchCommitResponse, error) | |||
BranchRollback(ctx context.Context, request *apis.BranchRollbackRequest) (*apis.BranchRollbackResponse, error) | |||
// RegisterResource Register a Resource to be managed by Resource Manager. | |||
RegisterResource(resource model.Resource) | |||
// UnregisterResource Unregister a Resource from the Resource Manager. | |||
UnregisterResource(resource model.Resource) | |||
// GetBranchType ... | |||
GetBranchType() apis.BranchSession_BranchType | |||
} | |||
type ResourceManager struct { | |||
addressing string | |||
rpcClient apis.ResourceManagerServiceClient | |||
managers map[apis.BranchSession_BranchType]ResourceManagerInterface | |||
branchMessages chan *apis.BranchMessage | |||
} | |||
func InitResourceManager(addressing string, client apis.ResourceManagerServiceClient) { | |||
defaultResourceManager = &ResourceManager{ | |||
addressing: addressing, | |||
rpcClient: client, | |||
managers: make(map[apis.BranchSession_BranchType]ResourceManagerInterface), | |||
branchMessages: make(chan *apis.BranchMessage), | |||
} | |||
runtime.GoWithRecover(func() { | |||
defaultResourceManager.branchCommunicate() | |||
}, nil) | |||
} | |||
func RegisterTransactionServiceServer(rm ResourceManagerInterface) { | |||
defaultResourceManager.managers[rm.GetBranchType()] = rm | |||
} | |||
func GetResourceManager() *ResourceManager { | |||
return defaultResourceManager | |||
} | |||
func (manager *ResourceManager) branchCommunicate() { | |||
for { | |||
ctx := metadata.AppendToOutgoingContext(context.Background(), "addressing", manager.addressing) | |||
stream, err := manager.rpcClient.BranchCommunicate(ctx) | |||
if err != nil { | |||
time.Sleep(time.Second) | |||
continue | |||
} | |||
done := make(chan bool) | |||
runtime.GoWithRecover(func() { | |||
for { | |||
select { | |||
case _, ok := <-done: | |||
if !ok { | |||
return | |||
} | |||
case msg := <-manager.branchMessages: | |||
err := stream.Send(msg) | |||
if err != nil { | |||
return | |||
} | |||
} | |||
} | |||
}, nil) | |||
for { | |||
msg, err := stream.Recv() | |||
if err == io.EOF { | |||
close(done) | |||
break | |||
} | |||
if err != nil { | |||
close(done) | |||
break | |||
} | |||
switch msg.BranchMessageType { | |||
case apis.TypeBranchCommit: | |||
request := &apis.BranchCommitRequest{} | |||
data := msg.GetMessage().GetValue() | |||
err := request.Unmarshal(data) | |||
if err != nil { | |||
log.Error(err) | |||
continue | |||
} | |||
response, err := manager.BranchCommit(context.Background(), request) | |||
if err == nil { | |||
content, err := types.MarshalAny(response) | |||
if err == nil { | |||
manager.branchMessages <- &apis.BranchMessage{ | |||
ID: msg.ID, | |||
BranchMessageType: apis.TypeBranchCommitResult, | |||
Message: content, | |||
} | |||
} | |||
} | |||
case apis.TypeBranchRollback: | |||
request := &apis.BranchRollbackRequest{} | |||
data := msg.GetMessage().GetValue() | |||
err := request.Unmarshal(data) | |||
if err != nil { | |||
log.Error(err) | |||
continue | |||
} | |||
response, err := manager.BranchRollback(context.Background(), request) | |||
if err == nil { | |||
content, err := types.MarshalAny(response) | |||
if err == nil { | |||
manager.branchMessages <- &apis.BranchMessage{ | |||
ID: msg.ID, | |||
BranchMessageType: apis.TypeBranchRollBackResult, | |||
Message: content, | |||
} | |||
} | |||
} | |||
} | |||
} | |||
err = stream.CloseSend() | |||
if err != nil { | |||
log.Error(err) | |||
} | |||
} | |||
} | |||
func (manager *ResourceManager) BranchRegister(ctx context.Context, xid string, resourceID string, | |||
branchType apis.BranchSession_BranchType, applicationData []byte, lockKeys string, asyncCommit bool) (int64, error) { | |||
request := &apis.BranchRegisterRequest{ | |||
Addressing: manager.addressing, | |||
XID: xid, | |||
ResourceID: resourceID, | |||
LockKey: lockKeys, | |||
BranchType: branchType, | |||
ApplicationData: applicationData, | |||
AsyncCommit: asyncCommit, | |||
} | |||
resp, err := manager.rpcClient.BranchRegister(ctx, request) | |||
if err != nil { | |||
return 0, err | |||
} | |||
if resp.ResultCode == apis.ResultCodeSuccess { | |||
return resp.BranchID, nil | |||
} | |||
return 0, &exception.TransactionException{ | |||
Code: resp.GetExceptionCode(), | |||
Message: resp.GetMessage(), | |||
} | |||
} | |||
func (manager *ResourceManager) BranchReport(ctx context.Context, xid string, branchID int64, | |||
branchType apis.BranchSession_BranchType, status apis.BranchSession_BranchStatus, applicationData []byte) error { | |||
request := &apis.BranchReportRequest{ | |||
XID: xid, | |||
BranchID: branchID, | |||
BranchType: branchType, | |||
BranchStatus: status, | |||
ApplicationData: applicationData, | |||
} | |||
resp, err := manager.rpcClient.BranchReport(ctx, request) | |||
if err != nil { | |||
return err | |||
} | |||
if resp.ResultCode == apis.ResultCodeFailed { | |||
return &exception.TransactionException{ | |||
Code: resp.GetExceptionCode(), | |||
Message: resp.GetMessage(), | |||
} | |||
} | |||
return nil | |||
} | |||
func (manager *ResourceManager) LockQuery(ctx context.Context, xid string, resourceID string, branchType apis.BranchSession_BranchType, | |||
lockKeys string) (bool, error) { | |||
request := &apis.GlobalLockQueryRequest{ | |||
XID: xid, | |||
ResourceID: resourceID, | |||
LockKey: lockKeys, | |||
BranchType: branchType, | |||
} | |||
resp, err := manager.rpcClient.LockQuery(ctx, request) | |||
if err != nil { | |||
return false, err | |||
} | |||
if resp.ResultCode == apis.ResultCodeSuccess { | |||
return resp.Lockable, nil | |||
} | |||
return false, &exception.TransactionException{ | |||
Code: resp.GetExceptionCode(), | |||
Message: resp.GetMessage(), | |||
} | |||
} | |||
func (manager ResourceManager) BranchCommit(ctx context.Context, request *apis.BranchCommitRequest) (*apis.BranchCommitResponse, error) { | |||
rm, ok := manager.managers[request.BranchType] | |||
if ok { | |||
return rm.BranchCommit(ctx, request) | |||
} | |||
return &apis.BranchCommitResponse{ | |||
ResultCode: apis.ResultCodeFailed, | |||
Message: fmt.Sprintf("there is no resource manager for %s", request.BranchType.String()), | |||
}, nil | |||
} | |||
func (manager *ResourceManager) BranchRollback(ctx context.Context, request *apis.BranchRollbackRequest) (*apis.BranchRollbackResponse, error) { | |||
rm, ok := manager.managers[request.BranchType] | |||
if ok { | |||
return rm.BranchRollback(ctx, request) | |||
} | |||
return &apis.BranchRollbackResponse{ | |||
ResultCode: apis.ResultCodeFailed, | |||
Message: fmt.Sprintf("there is no resource manager for %s", request.BranchType.String()), | |||
}, nil | |||
} | |||
func (manager *ResourceManager) RegisterResource(resource model.Resource) { | |||
rm := manager.managers[resource.GetBranchType()] | |||
rm.RegisterResource(resource) | |||
} | |||
func (manager *ResourceManager) UnregisterResource(resource model.Resource) { | |||
rm := manager.managers[resource.GetBranchType()] | |||
rm.UnregisterResource(resource) | |||
} |
@@ -0,0 +1,179 @@ | |||
package tcc | |||
import ( | |||
"encoding/json" | |||
"reflect" | |||
gxnet "github.com/dubbogo/gost/net" | |||
"github.com/pkg/errors" | |||
"github.com/opentrx/seata-golang/v2/pkg/apis" | |||
ctx "github.com/opentrx/seata-golang/v2/pkg/client/base/context" | |||
"github.com/opentrx/seata-golang/v2/pkg/client/proxy" | |||
"github.com/opentrx/seata-golang/v2/pkg/client/rm" | |||
"github.com/opentrx/seata-golang/v2/pkg/util/log" | |||
"github.com/opentrx/seata-golang/v2/pkg/util/time" | |||
) | |||
var ( | |||
TccActionName = "TccActionName" | |||
TryMethod = "Try" | |||
ConfirmMethod = "Confirm" | |||
CancelMethod = "Cancel" | |||
ActionStartTime = "action-start-time" | |||
ActionName = "actionName" | |||
PrepareMethod = "sys::prepare" | |||
CommitMethod = "sys::commit" | |||
RollbackMethod = "sys::rollback" | |||
HostName = "host-name" | |||
TccMethodArguments = "arguments" | |||
TccMethodResult = "result" | |||
businessActionContextType = reflect.TypeOf(&ctx.BusinessActionContext{}) | |||
) | |||
type TccService interface { | |||
Try(ctx *ctx.BusinessActionContext, async bool) (bool, error) | |||
Confirm(ctx *ctx.BusinessActionContext) bool | |||
Cancel(ctx *ctx.BusinessActionContext) bool | |||
} | |||
type TccProxyService interface { | |||
GetTccService() TccService | |||
} | |||
func ImplementTCC(v TccProxyService) { | |||
valueOf := reflect.ValueOf(v) | |||
log.Debugf("[implement] reflect.TypeOf: %s", valueOf.String()) | |||
valueOfElem := valueOf.Elem() | |||
typeOf := valueOfElem.Type() | |||
// check incoming interface, incoming interface's elem must be a struct. | |||
if typeOf.Kind() != reflect.Struct { | |||
log.Errorf("%s must be a struct ptr", valueOf.String()) | |||
return | |||
} | |||
proxyService := v.GetTccService() | |||
makeCallProxy := func(methodDesc *proxy.MethodDescriptor, resource *TCCResource) func(in []reflect.Value) []reflect.Value { | |||
return func(in []reflect.Value) []reflect.Value { | |||
businessContextValue := in[0] | |||
businessActionContext := businessContextValue.Interface().(*ctx.BusinessActionContext) | |||
rootContext := businessActionContext.RootContext | |||
businessActionContext.XID = rootContext.GetXID() | |||
businessActionContext.ActionName = resource.ActionName | |||
if !rootContext.InGlobalTransaction() { | |||
args := make([]interface{}, 0) | |||
args = append(args, businessActionContext) | |||
return proxy.Invoke(methodDesc, nil, args) | |||
} | |||
returnValues, err := proceed(methodDesc, businessActionContext, resource) | |||
if err != nil { | |||
return proxy.ReturnWithError(methodDesc, errors.WithStack(err)) | |||
} | |||
return returnValues | |||
} | |||
} | |||
numField := valueOfElem.NumField() | |||
for i := 0; i < numField; i++ { | |||
t := typeOf.Field(i) | |||
methodName := t.Name | |||
f := valueOfElem.Field(i) | |||
if f.Kind() == reflect.Func && f.IsValid() && f.CanSet() && methodName == TryMethod { | |||
if t.Type.NumIn() != 1 && t.Type.In(0) != businessActionContextType { | |||
panic("prepare method argument is not BusinessActionContext") | |||
} | |||
actionName := t.Tag.Get(TccActionName) | |||
if actionName == "" { | |||
panic("must tag TccActionName") | |||
} | |||
commitMethodDesc := proxy.Register(proxyService, ConfirmMethod) | |||
cancelMethodDesc := proxy.Register(proxyService, CancelMethod) | |||
tryMethodDesc := proxy.Register(proxyService, methodName) | |||
tccResource := &TCCResource{ | |||
ActionName: actionName, | |||
PrepareMethodName: TryMethod, | |||
CommitMethodName: ConfirmMethod, | |||
CommitMethod: commitMethodDesc, | |||
RollbackMethodName: CancelMethod, | |||
RollbackMethod: cancelMethodDesc, | |||
} | |||
tccResourceManager.RegisterResource(tccResource) | |||
// do method proxy here: | |||
f.Set(reflect.MakeFunc(f.Type(), makeCallProxy(tryMethodDesc, tccResource))) | |||
log.Debugf("set method [%s]", methodName) | |||
} | |||
} | |||
} | |||
func proceed(methodDesc *proxy.MethodDescriptor, ctx *ctx.BusinessActionContext, resource *TCCResource) ([]reflect.Value, error) { | |||
var ( | |||
args = make([]interface{}, 0) | |||
) | |||
branchID, err := doTccActionLogStore(ctx, resource) | |||
if err != nil { | |||
return nil, errors.WithStack(err) | |||
} | |||
ctx.BranchID = branchID | |||
args = append(args, ctx) | |||
returnValues := proxy.Invoke(methodDesc, nil, args) | |||
errValue := returnValues[len(returnValues)-1] | |||
if errValue.IsValid() && !errValue.IsNil() { | |||
err := rm.GetResourceManager().BranchReport(ctx.RootContext, ctx.XID, branchID, apis.TCC, apis.PhaseOneFailed, nil) | |||
if err != nil { | |||
log.Errorf("branch report err: %v", err) | |||
} | |||
} | |||
return returnValues, nil | |||
} | |||
func doTccActionLogStore(ctx *ctx.BusinessActionContext, resource *TCCResource) (int64, error) { | |||
ctx.ActionContext[ActionStartTime] = time.CurrentTimeMillis() | |||
ctx.ActionContext[PrepareMethod] = resource.PrepareMethodName | |||
ctx.ActionContext[CommitMethod] = resource.CommitMethodName | |||
ctx.ActionContext[RollbackMethod] = resource.RollbackMethodName | |||
ctx.ActionContext[ActionName] = ctx.ActionName | |||
ip, err := gxnet.GetLocalIP() | |||
if err == nil { | |||
ctx.ActionContext[HostName] = ip | |||
} else { | |||
log.Warn("getLocalIP error") | |||
} | |||
applicationContext := make(map[string]interface{}) | |||
applicationContext[TccActionContext] = ctx.ActionContext | |||
applicationData, err := json.Marshal(applicationContext) | |||
if err != nil { | |||
log.Errorf("marshal applicationContext failed:%v", applicationContext) | |||
return 0, err | |||
} | |||
branchID, err := rm.GetResourceManager().BranchRegister( | |||
ctx.RootContext, | |||
ctx.XID, | |||
resource.GetResourceID(), | |||
resource.GetBranchType(), | |||
applicationData, | |||
"", | |||
ctx.AsyncCommit, | |||
) | |||
if err != nil { | |||
log.Errorf("TCC branch Register error, xid: %s", ctx.XID) | |||
return 0, errors.WithStack(err) | |||
} | |||
return branchID, nil | |||
} |
@@ -0,0 +1,23 @@ | |||
package tcc | |||
import ( | |||
"github.com/opentrx/seata-golang/v2/pkg/apis" | |||
"github.com/opentrx/seata-golang/v2/pkg/client/proxy" | |||
) | |||
type TCCResource struct { | |||
ActionName string | |||
PrepareMethodName string | |||
CommitMethodName string | |||
CommitMethod *proxy.MethodDescriptor | |||
RollbackMethodName string | |||
RollbackMethod *proxy.MethodDescriptor | |||
} | |||
func (resource *TCCResource) GetResourceID() string { | |||
return resource.ActionName | |||
} | |||
func (resource *TCCResource) GetBranchType() apis.BranchSession_BranchType { | |||
return apis.TCC | |||
} |
@@ -0,0 +1,153 @@ | |||
package tcc | |||
import ( | |||
"context" | |||
"encoding/json" | |||
"fmt" | |||
"github.com/opentrx/seata-golang/v2/pkg/apis" | |||
ctx "github.com/opentrx/seata-golang/v2/pkg/client/base/context" | |||
"github.com/opentrx/seata-golang/v2/pkg/client/base/model" | |||
"github.com/opentrx/seata-golang/v2/pkg/client/proxy" | |||
"github.com/opentrx/seata-golang/v2/pkg/util/log" | |||
) | |||
var ( | |||
TccActionContext = "actionContext" | |||
) | |||
var tccResourceManager TCCResourceManager | |||
type TCCResourceManager struct { | |||
ResourceCache map[string]model.Resource | |||
} | |||
func init() { | |||
tccResourceManager = TCCResourceManager{ResourceCache: make(map[string]model.Resource)} | |||
} | |||
func GetTCCResourceManager() TCCResourceManager { | |||
return tccResourceManager | |||
} | |||
func (resourceManager TCCResourceManager) BranchCommit(ctx context.Context, request *apis.BranchCommitRequest) (*apis.BranchCommitResponse, error) { | |||
resource := resourceManager.ResourceCache[request.ResourceID] | |||
if resource == nil { | |||
log.Errorf("TCC resource is not exist, resourceID: %s", request.ResourceID) | |||
return &apis.BranchCommitResponse{ | |||
ResultCode: apis.ResultCodeFailed, | |||
Message: fmt.Sprintf("TCC resource is not exist, resourceID: %s", request.ResourceID), | |||
}, nil | |||
} | |||
tccResource := resource.(*TCCResource) | |||
if tccResource.CommitMethod == nil { | |||
log.Errorf("TCC resource is not available, resourceID: %s", request.ResourceID) | |||
return &apis.BranchCommitResponse{ | |||
ResultCode: apis.ResultCodeFailed, | |||
Message: fmt.Sprintf("TCC resource is not available, resourceID: %s", request.ResourceID), | |||
}, nil | |||
} | |||
result := false | |||
businessActionContext := getBusinessActionContext(request.XID, request.BranchID, request.ResourceID, request.ApplicationData) | |||
args := make([]interface{}, 0) | |||
args = append(args, businessActionContext) | |||
returnValues := proxy.Invoke(tccResource.CommitMethod, nil, args) | |||
log.Debugf("TCC resource commit result : %v, xid: %s, branchID: %d, resourceID: %s", returnValues, request.XID, request.BranchID, request.ResourceID) | |||
if len(returnValues) == 1 { | |||
result = returnValues[0].Interface().(bool) | |||
} | |||
if result { | |||
return &apis.BranchCommitResponse{ | |||
ResultCode: apis.ResultCodeSuccess, | |||
XID: request.XID, | |||
BranchID: request.BranchID, | |||
BranchStatus: apis.PhaseTwoCommitted, | |||
}, nil | |||
} | |||
return &apis.BranchCommitResponse{ | |||
ResultCode: apis.ResultCodeSuccess, | |||
XID: request.XID, | |||
BranchID: request.BranchID, | |||
BranchStatus: apis.PhaseTwoCommitFailedRetryable, | |||
}, nil | |||
} | |||
func (resourceManager TCCResourceManager) BranchRollback(ctx context.Context, request *apis.BranchRollbackRequest) (*apis.BranchRollbackResponse, error) { | |||
resource := resourceManager.ResourceCache[request.ResourceID] | |||
if resource == nil { | |||
return &apis.BranchRollbackResponse{ | |||
ResultCode: apis.ResultCodeFailed, | |||
Message: fmt.Sprintf("TCC resource is not exist, resourceID: %s", request.ResourceID), | |||
}, nil | |||
} | |||
tccResource := resource.(*TCCResource) | |||
if tccResource.RollbackMethod == nil { | |||
return &apis.BranchRollbackResponse{ | |||
ResultCode: apis.ResultCodeFailed, | |||
Message: fmt.Sprintf("TCC resource is not available, resourceID: %s", request.ResourceID), | |||
}, nil | |||
} | |||
result := false | |||
businessActionContext := getBusinessActionContext(request.XID, request.BranchID, request.ResourceID, request.ApplicationData) | |||
args := make([]interface{}, 0) | |||
args = append(args, businessActionContext) | |||
returnValues := proxy.Invoke(tccResource.RollbackMethod, nil, args) | |||
log.Debugf("TCC resource rollback result : %v, xid: %s, branchID: %d, resourceID: %s", returnValues, request.XID, request.BranchID, request.ResourceID) | |||
if len(returnValues) == 1 { | |||
result = returnValues[0].Interface().(bool) | |||
} | |||
if result { | |||
return &apis.BranchRollbackResponse{ | |||
ResultCode: apis.ResultCodeSuccess, | |||
XID: request.XID, | |||
BranchID: request.BranchID, | |||
BranchStatus: apis.PhaseTwoRolledBack, | |||
}, nil | |||
} | |||
return &apis.BranchRollbackResponse{ | |||
ResultCode: apis.ResultCodeSuccess, | |||
XID: request.XID, | |||
BranchID: request.BranchID, | |||
BranchStatus: apis.PhaseTwoRollbackFailedRetryable, | |||
}, nil | |||
} | |||
func getBusinessActionContext(xid string, branchID int64, resourceID string, applicationData []byte) *ctx.BusinessActionContext { | |||
var ( | |||
tccContext = make(map[string]interface{}) | |||
actionContextMap = make(map[string]interface{}) | |||
) | |||
if len(applicationData) > 0 { | |||
err := json.Unmarshal(applicationData, &tccContext) | |||
if err != nil { | |||
log.Errorf("getBusinessActionContext, unmarshal applicationData err=%v", err) | |||
} | |||
} | |||
acMap := tccContext[TccActionContext] | |||
if acMap != nil { | |||
actionContextMap = acMap.(map[string]interface{}) | |||
} | |||
businessActionContext := &ctx.BusinessActionContext{ | |||
XID: xid, | |||
BranchID: branchID, | |||
ActionName: resourceID, | |||
ActionContext: actionContextMap, | |||
} | |||
return businessActionContext | |||
} | |||
func (resourceManager TCCResourceManager) RegisterResource(resource model.Resource) { | |||
resourceManager.ResourceCache[resource.GetResourceID()] = resource | |||
} | |||
func (resourceManager TCCResourceManager) UnregisterResource(resource model.Resource) { | |||
delete(resourceManager.ResourceCache, resource.GetResourceID()) | |||
} | |||
func (resourceManager TCCResourceManager) GetBranchType() apis.BranchSession_BranchType { | |||
return apis.TCC | |||
} |
@@ -0,0 +1,261 @@ | |||
package tm | |||
import ( | |||
"fmt" | |||
"github.com/pkg/errors" | |||
"github.com/opentrx/seata-golang/v2/pkg/apis" | |||
ctx "github.com/opentrx/seata-golang/v2/pkg/client/base/context" | |||
"github.com/opentrx/seata-golang/v2/pkg/client/config" | |||
"github.com/opentrx/seata-golang/v2/pkg/util/log" | |||
) | |||
const ( | |||
DefaultGlobalTxTimeout = 60000 | |||
DefaultGlobalTxName = "default" | |||
) | |||
type SuspendedResourcesHolder struct { | |||
Xid string | |||
} | |||
type GlobalTransaction interface { | |||
Begin(ctx *ctx.RootContext) error | |||
BeginWithTimeout(timeout int32, ctx *ctx.RootContext) error | |||
BeginWithTimeoutAndName(timeout int32, name string, ctx *ctx.RootContext) error | |||
Commit(ctx *ctx.RootContext) error | |||
Rollback(ctx *ctx.RootContext) error | |||
Suspend(unbindXid bool, ctx *ctx.RootContext) (*SuspendedResourcesHolder, error) | |||
Resume(suspendedResourcesHolder *SuspendedResourcesHolder, ctx *ctx.RootContext) error | |||
GetStatus(ctx *ctx.RootContext) (apis.GlobalSession_GlobalStatus, error) | |||
GetXid(ctx *ctx.RootContext) string | |||
GlobalReport(globalStatus apis.GlobalSession_GlobalStatus, ctx *ctx.RootContext) error | |||
GetLocalStatus() apis.GlobalSession_GlobalStatus | |||
} | |||
type GlobalTransactionRole byte | |||
const ( | |||
// The Launcher. The one begins the current global transaction. | |||
Launcher GlobalTransactionRole = iota | |||
// The Participant. The one just joins into a existing global transaction. | |||
Participant | |||
) | |||
func (role GlobalTransactionRole) String() string { | |||
switch role { | |||
case Launcher: | |||
return "Launcher" | |||
case Participant: | |||
return "Participant" | |||
default: | |||
return fmt.Sprintf("%d", role) | |||
} | |||
} | |||
type DefaultGlobalTransaction struct { | |||
conf config.TMConfig | |||
XID string | |||
Status apis.GlobalSession_GlobalStatus | |||
Role GlobalTransactionRole | |||
transactionManager TransactionManagerInterface | |||
} | |||
func (gtx *DefaultGlobalTransaction) Begin(ctx *ctx.RootContext) error { | |||
return gtx.BeginWithTimeout(DefaultGlobalTxTimeout, ctx) | |||
} | |||
func (gtx *DefaultGlobalTransaction) BeginWithTimeout(timeout int32, ctx *ctx.RootContext) error { | |||
return gtx.BeginWithTimeoutAndName(timeout, DefaultGlobalTxName, ctx) | |||
} | |||
func (gtx *DefaultGlobalTransaction) BeginWithTimeoutAndName(timeout int32, name string, ctx *ctx.RootContext) error { | |||
if gtx.Role != Launcher { | |||
if gtx.XID == "" { | |||
return errors.New("xid should not be empty") | |||
} | |||
log.Debugf("Ignore Begin(): just involved in global transaction [%s]", gtx.XID) | |||
return nil | |||
} | |||
if gtx.XID != "" { | |||
return errors.New("xid should be empty") | |||
} | |||
if ctx.InGlobalTransaction() { | |||
return errors.New("xid should be empty") | |||
} | |||
xid, err := gtx.transactionManager.Begin(ctx, name, timeout) | |||
if err != nil { | |||
return errors.WithStack(err) | |||
} | |||
gtx.XID = xid | |||
gtx.Status = apis.Begin | |||
ctx.Bind(xid) | |||
log.Infof("begin new global transaction [%s]", xid) | |||
return nil | |||
} | |||
func (gtx *DefaultGlobalTransaction) Commit(ctx *ctx.RootContext) error { | |||
defer func() { | |||
ctxXid := ctx.GetXID() | |||
if ctxXid != "" && gtx.XID == ctxXid { | |||
ctx.Unbind() | |||
} | |||
}() | |||
if gtx.Role == Participant { | |||
log.Debugf("ignore Commit(): just involved in global transaction [%s]", gtx.XID) | |||
return nil | |||
} | |||
if gtx.XID == "" { | |||
return errors.New("xid should not be empty") | |||
} | |||
retry := gtx.conf.CommitRetryCount | |||
for retry > 0 { | |||
status, err := gtx.transactionManager.Commit(ctx, gtx.XID) | |||
if err != nil { | |||
log.Errorf("failed to report global commit [%s],Retry Countdown: %d, reason: %s", gtx.XID, retry, err.Error()) | |||
} else { | |||
gtx.Status = status | |||
break | |||
} | |||
retry-- | |||
if retry == 0 { | |||
return errors.New("Failed to report global commit") | |||
} | |||
} | |||
log.Infof("[%s] commit status: %s", gtx.XID, gtx.Status.String()) | |||
return nil | |||
} | |||
func (gtx *DefaultGlobalTransaction) Rollback(ctx *ctx.RootContext) error { | |||
defer func() { | |||
ctxXid := ctx.GetXID() | |||
if ctxXid != "" && gtx.XID == ctxXid { | |||
ctx.Unbind() | |||
} | |||
}() | |||
if gtx.Role == Participant { | |||
log.Debugf("ignore Rollback(): just involved in global transaction [%s]", gtx.XID) | |||
return nil | |||
} | |||
if gtx.XID == "" { | |||
return errors.New("xid should not be empty") | |||
} | |||
retry := gtx.conf.RollbackRetryCount | |||
for retry > 0 { | |||
status, err := gtx.transactionManager.Rollback(ctx, gtx.XID) | |||
if err != nil { | |||
log.Errorf("failed to report global rollback [%s],Retry Countdown: %d, reason: %s", gtx.XID, retry, err.Error()) | |||
} else { | |||
gtx.Status = status | |||
break | |||
} | |||
retry-- | |||
if retry == 0 { | |||
return errors.New("Failed to report global rollback") | |||
} | |||
} | |||
log.Infof("[%s] rollback status: %s", gtx.XID, gtx.Status.String()) | |||
return nil | |||
} | |||
func (gtx *DefaultGlobalTransaction) Suspend(unbindXid bool, ctx *ctx.RootContext) (*SuspendedResourcesHolder, error) { | |||
xid := ctx.GetXID() | |||
if xid != "" && unbindXid { | |||
ctx.Unbind() | |||
log.Debugf("suspending current transaction,xid = %s", xid) | |||
} | |||
return &SuspendedResourcesHolder{Xid: xid}, nil | |||
} | |||
func (gtx *DefaultGlobalTransaction) Resume(suspendedResourcesHolder *SuspendedResourcesHolder, ctx *ctx.RootContext) error { | |||
if suspendedResourcesHolder == nil { | |||
return nil | |||
} | |||
xid := suspendedResourcesHolder.Xid | |||
if xid != "" { | |||
ctx.Bind(xid) | |||
log.Debugf("resuming the transaction,xid = %s", xid) | |||
} | |||
return nil | |||
} | |||
func (gtx *DefaultGlobalTransaction) GetStatus(ctx *ctx.RootContext) (apis.GlobalSession_GlobalStatus, error) { | |||
if gtx.XID == "" { | |||
return apis.UnknownGlobalStatus, nil | |||
} | |||
status, err := gtx.transactionManager.GetStatus(ctx, gtx.XID) | |||
if err != nil { | |||
return 0, errors.WithStack(err) | |||
} | |||
gtx.Status = status | |||
return gtx.Status, nil | |||
} | |||
func (gtx *DefaultGlobalTransaction) GetXid(ctx *ctx.RootContext) string { | |||
return gtx.XID | |||
} | |||
func (gtx *DefaultGlobalTransaction) GlobalReport(globalStatus apis.GlobalSession_GlobalStatus, ctx *ctx.RootContext) error { | |||
defer func() { | |||
ctxXid := ctx.GetXID() | |||
if ctxXid != "" && gtx.XID == ctxXid { | |||
ctx.Unbind() | |||
} | |||
}() | |||
if gtx.XID == "" { | |||
return errors.New("xid should not be empty") | |||
} | |||
if globalStatus == 0 { | |||
return errors.New("globalStatus should not be zero") | |||
} | |||
status, err := gtx.transactionManager.GlobalReport(ctx, gtx.XID, globalStatus) | |||
if err != nil { | |||
return errors.WithStack(err) | |||
} | |||
gtx.Status = status | |||
log.Infof("[%s] report status: %s", gtx.XID, gtx.Status.String()) | |||
return nil | |||
} | |||
func (gtx *DefaultGlobalTransaction) GetLocalStatus() apis.GlobalSession_GlobalStatus { | |||
return gtx.Status | |||
} | |||
func CreateNew() *DefaultGlobalTransaction { | |||
return &DefaultGlobalTransaction{ | |||
conf: config.GetTMConfig(), | |||
XID: "", | |||
Status: apis.UnknownGlobalStatus, | |||
Role: Launcher, | |||
transactionManager: defaultTransactionManager, | |||
} | |||
} | |||
func GetCurrent(ctx *ctx.RootContext) *DefaultGlobalTransaction { | |||
xid := ctx.GetXID() | |||
if xid == "" { | |||
return nil | |||
} | |||
return &DefaultGlobalTransaction{ | |||
conf: config.GetTMConfig(), | |||
XID: xid, | |||
Status: apis.Begin, | |||
Role: Participant, | |||
transactionManager: defaultTransactionManager, | |||
} | |||
} | |||
func GetCurrentOrCreate(ctx *ctx.RootContext) *DefaultGlobalTransaction { | |||
tx := GetCurrent(ctx) | |||
if tx == nil { | |||
return CreateNew() | |||
} | |||
return tx | |||
} |
@@ -0,0 +1,151 @@ | |||
package tm | |||
import ( | |||
"context" | |||
"reflect" | |||
"github.com/pkg/errors" | |||
ctx "github.com/opentrx/seata-golang/v2/pkg/client/base/context" | |||
"github.com/opentrx/seata-golang/v2/pkg/client/base/model" | |||
"github.com/opentrx/seata-golang/v2/pkg/client/proxy" | |||
"github.com/opentrx/seata-golang/v2/pkg/util/log" | |||
) | |||
type GlobalTransactionProxyService interface { | |||
GetProxyService() interface{} | |||
GetMethodTransactionInfo(methodName string) *model.TransactionInfo | |||
} | |||
var ( | |||
typError = reflect.Zero(reflect.TypeOf((*error)(nil)).Elem()).Type() | |||
) | |||
func Implement(v GlobalTransactionProxyService) { | |||
valueOf := reflect.ValueOf(v) | |||
log.Debugf("[implement] reflect.TypeOf: %s", valueOf.String()) | |||
valueOfElem := valueOf.Elem() | |||
typeOf := valueOfElem.Type() | |||
// check incoming interface, incoming interface's elem must be a struct. | |||
if typeOf.Kind() != reflect.Struct { | |||
log.Errorf("%s must be a struct ptr", valueOf.String()) | |||
return | |||
} | |||
proxyService := v.GetProxyService() | |||
makeCallProxy := func(methodDesc *proxy.MethodDescriptor, txInfo *model.TransactionInfo) func(in []reflect.Value) []reflect.Value { | |||
return func(in []reflect.Value) []reflect.Value { | |||
var ( | |||
args []interface{} | |||
returnValues []reflect.Value | |||
suspendedResourcesHolder *SuspendedResourcesHolder | |||
) | |||
if txInfo == nil { | |||
// testing phase, this problem should be resolved | |||
panic(errors.New("transactionInfo does not exist")) | |||
} | |||
inNum := len(in) | |||
if inNum+1 != methodDesc.ArgsNum { | |||
// testing phase, this problem should be resolved | |||
panic(errors.New("args does not match")) | |||
} | |||
invCtx := ctx.NewRootContext(context.Background()) | |||
for i := 0; i < inNum; i++ { | |||
if in[i].Type().String() == "context.Context" { | |||
if !in[i].IsNil() { | |||
// the user declared context as method's parameter | |||
invCtx = ctx.NewRootContext(in[i].Interface().(context.Context)) | |||
} | |||
} | |||
args = append(args, in[i].Interface()) | |||
} | |||
tx := GetCurrentOrCreate(invCtx) | |||
defer func() { | |||
err := tx.Resume(suspendedResourcesHolder, invCtx) | |||
if err != nil { | |||
log.Error(err) | |||
} | |||
}() | |||
switch txInfo.Propagation { | |||
case model.Required: | |||
case model.RequiresNew: | |||
suspendedResourcesHolder, _ = tx.Suspend(true, invCtx) | |||
case model.NotSupported: | |||
suspendedResourcesHolder, _ = tx.Suspend(true, invCtx) | |||
returnValues = proxy.Invoke(methodDesc, invCtx, args) | |||
return returnValues | |||
case model.Supports: | |||
if !invCtx.InGlobalTransaction() { | |||
returnValues = proxy.Invoke(methodDesc, invCtx, args) | |||
return returnValues | |||
} | |||
case model.Never: | |||
if invCtx.InGlobalTransaction() { | |||
return proxy.ReturnWithError(methodDesc, errors.Errorf("Existing transaction found for transaction marked with propagation 'never',xid = %s", invCtx.GetXID())) | |||
} | |||
returnValues = proxy.Invoke(methodDesc, invCtx, args) | |||
return returnValues | |||
case model.Mandatory: | |||
if !invCtx.InGlobalTransaction() { | |||
return proxy.ReturnWithError(methodDesc, errors.New("No existing transaction found for transaction marked with propagation 'mandatory'")) | |||
} | |||
default: | |||
return proxy.ReturnWithError(methodDesc, errors.Errorf("Not Supported Propagation: %s", txInfo.Propagation.String())) | |||
} | |||
beginErr := tx.BeginWithTimeoutAndName(txInfo.TimeOut, txInfo.Name, invCtx) | |||
if beginErr != nil { | |||
return proxy.ReturnWithError(methodDesc, errors.WithStack(beginErr)) | |||
} | |||
returnValues = proxy.Invoke(methodDesc, invCtx, args) | |||
errValue := returnValues[len(returnValues)-1] | |||
// todo 只要出错就回滚,未来可以优化一下,某些错误才回滚,某些错误的情况下,可以提交 | |||
if errValue.IsValid() && !errValue.IsNil() { | |||
rollbackErr := tx.Rollback(invCtx) | |||
if rollbackErr != nil { | |||
return proxy.ReturnWithError(methodDesc, errors.WithStack(rollbackErr)) | |||
} | |||
return returnValues | |||
} | |||
commitErr := tx.Commit(invCtx) | |||
if commitErr != nil { | |||
return proxy.ReturnWithError(methodDesc, errors.WithStack(commitErr)) | |||
} | |||
return returnValues | |||
} | |||
} | |||
numField := valueOfElem.NumField() | |||
for i := 0; i < numField; i++ { | |||
t := typeOf.Field(i) | |||
methodName := t.Name | |||
f := valueOfElem.Field(i) | |||
if f.Kind() == reflect.Func && f.IsValid() && f.CanSet() { | |||
outNum := t.Type.NumOut() | |||
// The latest return type of the method must be error. | |||
if returnType := t.Type.Out(outNum - 1); returnType != typError { | |||
log.Warnf("the latest return type %s of method %q is not error", returnType, t.Name) | |||
continue | |||
} | |||
methodDescriptor := proxy.Register(proxyService, methodName) | |||
// do method proxy here: | |||
f.Set(reflect.MakeFunc(f.Type(), makeCallProxy(methodDescriptor, v.GetMethodTransactionInfo(methodName)))) | |||
log.Debugf("set method [%s]", methodName) | |||
} | |||
} | |||
} |
@@ -0,0 +1,125 @@ | |||
package tm | |||
import ( | |||
"context" | |||
"github.com/opentrx/seata-golang/v2/pkg/apis" | |||
"github.com/opentrx/seata-golang/v2/pkg/client/base/exception" | |||
) | |||
var defaultTransactionManager *TransactionManager | |||
type TransactionManagerInterface interface { | |||
// GlobalStatus_Begin a new global transaction. | |||
Begin(ctx context.Context, name string, timeout int32) (string, error) | |||
// Global commit. | |||
Commit(ctx context.Context, xid string) (apis.GlobalSession_GlobalStatus, error) | |||
// Global rollback. | |||
Rollback(ctx context.Context, xid string) (apis.GlobalSession_GlobalStatus, error) | |||
// Get current status of the give transaction. | |||
GetStatus(ctx context.Context, xid string) (apis.GlobalSession_GlobalStatus, error) | |||
// Global report. | |||
GlobalReport(ctx context.Context, xid string, globalStatus apis.GlobalSession_GlobalStatus) (apis.GlobalSession_GlobalStatus, error) | |||
} | |||
type TransactionManager struct { | |||
addressing string | |||
rpcClient apis.TransactionManagerServiceClient | |||
} | |||
func InitTransactionManager(addressing string, client apis.TransactionManagerServiceClient) { | |||
defaultTransactionManager = &TransactionManager{ | |||
addressing: addressing, | |||
rpcClient: client, | |||
} | |||
} | |||
func GetTransactionManager() *TransactionManager { | |||
return defaultTransactionManager | |||
} | |||
func (manager *TransactionManager) Begin(ctx context.Context, name string, timeout int32) (string, error) { | |||
request := &apis.GlobalBeginRequest{ | |||
Addressing: manager.addressing, | |||
Timeout: timeout, | |||
TransactionName: name, | |||
} | |||
resp, err := manager.rpcClient.Begin(ctx, request) | |||
if err != nil { | |||
return "", err | |||
} | |||
if resp.ResultCode == apis.ResultCodeSuccess { | |||
return resp.XID, nil | |||
} | |||
return "", &exception.TransactionException{ | |||
Code: resp.GetExceptionCode(), | |||
Message: resp.GetMessage(), | |||
} | |||
} | |||
func (manager *TransactionManager) Commit(ctx context.Context, xid string) (apis.GlobalSession_GlobalStatus, error) { | |||
request := &apis.GlobalCommitRequest{XID: xid} | |||
resp, err := manager.rpcClient.Commit(ctx, request) | |||
if err != nil { | |||
return 0, err | |||
} | |||
if resp.ResultCode == apis.ResultCodeSuccess { | |||
return resp.GlobalStatus, nil | |||
} | |||
return 0, &exception.TransactionException{ | |||
Code: resp.GetExceptionCode(), | |||
Message: resp.GetMessage(), | |||
} | |||
} | |||
func (manager *TransactionManager) Rollback(ctx context.Context, xid string) (apis.GlobalSession_GlobalStatus, error) { | |||
request := &apis.GlobalRollbackRequest{XID: xid} | |||
resp, err := manager.rpcClient.Rollback(ctx, request) | |||
if err != nil { | |||
return 0, err | |||
} | |||
if resp.ResultCode == apis.ResultCodeSuccess { | |||
return resp.GlobalStatus, nil | |||
} | |||
return 0, &exception.TransactionException{ | |||
Code: resp.GetExceptionCode(), | |||
Message: resp.GetMessage(), | |||
} | |||
} | |||
func (manager *TransactionManager) GetStatus(ctx context.Context, xid string) (apis.GlobalSession_GlobalStatus, error) { | |||
request := &apis.GlobalStatusRequest{XID: xid} | |||
resp, err := manager.rpcClient.GetStatus(context.Background(), request) | |||
if err != nil { | |||
return 0, err | |||
} | |||
if resp.ResultCode == apis.ResultCodeSuccess { | |||
return resp.GlobalStatus, nil | |||
} | |||
return 0, &exception.TransactionException{ | |||
Code: resp.GetExceptionCode(), | |||
Message: resp.GetMessage(), | |||
} | |||
} | |||
func (manager *TransactionManager) GlobalReport(ctx context.Context, xid string, globalStatus apis.GlobalSession_GlobalStatus) (apis.GlobalSession_GlobalStatus, error) { | |||
request := &apis.GlobalReportRequest{ | |||
XID: xid, | |||
GlobalStatus: globalStatus, | |||
} | |||
resp, err := manager.rpcClient.GlobalReport(ctx, request) | |||
if err != nil { | |||
return 0, err | |||
} | |||
if resp.ResultCode == apis.ResultCodeSuccess { | |||
return resp.GlobalStatus, nil | |||
} | |||
return 0, &exception.TransactionException{ | |||
Code: resp.GetExceptionCode(), | |||
Message: resp.GetMessage(), | |||
} | |||
} |
@@ -0,0 +1,19 @@ | |||
package common | |||
import "github.com/opentrx/seata-golang/v2/pkg/apis" | |||
// MessageFuture ... | |||
type MessageFuture struct { | |||
ID int64 | |||
Err error | |||
Response interface{} | |||
Done chan bool | |||
} | |||
// NewMessageFuture ... | |||
func NewMessageFuture(message *apis.BranchMessage) *MessageFuture { | |||
return &MessageFuture{ | |||
ID: message.ID, | |||
Done: make(chan bool), | |||
} | |||
} |
@@ -1,18 +0,0 @@ | |||
/* | |||
* Licensed to the Apache Software Foundation (ASF) under one or more | |||
* contributor license agreements. See the NOTICE file distributed with | |||
* this work for additional information regarding copyright ownership. | |||
* The ASF licenses this file to You under the Apache License, Version 2.0 | |||
* (the "License"); you may not use this file except in compliance with | |||
* the License. You may obtain a copy of the License at | |||
* | |||
* http://www.apache.org/licenses/LICENSE-2.0 | |||
* | |||
* Unless required by applicable law or agreed to in writing, software | |||
* distributed under the License is distributed on an "AS IS" BASIS, | |||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
* See the License for the specific language governing permissions and | |||
* limitations under the License. | |||
*/ | |||
package compressor |
@@ -1,67 +0,0 @@ | |||
/* | |||
* Licensed to the Apache Software Foundation (ASF) under one or more | |||
* contributor license agreements. See the NOTICE file distributed with | |||
* this work for additional information regarding copyright ownership. | |||
* The ASF licenses this file to You under the Apache License, Version 2.0 | |||
* (the "License"); you may not use this file except in compliance with | |||
* the License. You may obtain a copy of the License at | |||
* | |||
* http://www.apache.org/licenses/LICENSE-2.0 | |||
* | |||
* Unless required by applicable law or agreed to in writing, software | |||
* distributed under the License is distributed on an "AS IS" BASIS, | |||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
* See the License for the specific language governing permissions and | |||
* limitations under the License. | |||
*/ | |||
package compressor | |||
import ( | |||
"bytes" | |||
"io/ioutil" | |||
"github.com/dsnet/compress/bzip2" | |||
) | |||
type Bzip2 struct { | |||
} | |||
// Compress Bzip2 compress | |||
func (g *Bzip2) Compress(b []byte) ([]byte, error) { | |||
var buffer bytes.Buffer | |||
gz, err := bzip2.NewWriter(&buffer, &bzip2.WriterConfig{Level: bzip2.DefaultCompression}) | |||
if err != nil { | |||
return nil, err | |||
} | |||
if _, err := gz.Write(b); err != nil { | |||
return nil, err | |||
} | |||
if err := gz.Close(); err != nil { | |||
return nil, err | |||
} | |||
return buffer.Bytes(), nil | |||
} | |||
// Decompress Bzip2 decompress | |||
func (g *Bzip2) Decompress(in []byte) ([]byte, error) { | |||
reader, err := bzip2.NewReader(bytes.NewReader(in), nil) | |||
if err != nil { | |||
return nil, err | |||
} | |||
if err = reader.Close(); err != nil { | |||
return nil, err | |||
} | |||
output, err := ioutil.ReadAll(reader) | |||
if err != nil { | |||
return nil, err | |||
} | |||
return output, nil | |||
} | |||
func (g *Bzip2) GetCompressorType() CompressorType { | |||
return CompressorBzip2 | |||
} |
@@ -1,40 +0,0 @@ | |||
/* | |||
* Licensed to the Apache Software Foundation (ASF) under one or more | |||
* contributor license agreements. See the NOTICE file distributed with | |||
* this work for additional information regarding copyright ownership. | |||
* The ASF licenses this file to You under the Apache License, Version 2.0 | |||
* (the "License"); you may not use this file except in compliance with | |||
* the License. You may obtain a copy of the License at | |||
* | |||
* http://www.apache.org/licenses/LICENSE-2.0 | |||
* | |||
* Unless required by applicable law or agreed to in writing, software | |||
* distributed under the License is distributed on an "AS IS" BASIS, | |||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
* See the License for the specific language governing permissions and | |||
* limitations under the License. | |||
*/ | |||
package compressor | |||
import ( | |||
"strings" | |||
"testing" | |||
"github.com/stretchr/testify/assert" | |||
) | |||
func TestBzip2Compress(t *testing.T) { | |||
str := strings.Repeat(" bzip2 ", 100) | |||
b := &Bzip2{} | |||
compressRes, err := b.Compress([]byte(str)) | |||
assert.NoError(t, err) | |||
t.Logf("compress res: %v", string(compressRes)) | |||
decompressRes, err := b.Decompress(compressRes) | |||
assert.NoError(t, err) | |||
assert.Equal(t, str, string(decompressRes)) | |||
t.Logf("decompress res: %v", string(decompressRes)) | |||
} |
@@ -1,24 +0,0 @@ | |||
/* | |||
* Licensed to the Apache Software Foundation (ASF) under one or more | |||
* contributor license agreements. See the NOTICE file distributed with | |||
* this work for additional information regarding copyright ownership. | |||
* The ASF licenses this file to You under the Apache License, Version 2.0 | |||
* (the "License"); you may not use this file except in compliance with | |||
* the License. You may obtain a copy of the License at | |||
* | |||
* http://www.apache.org/licenses/LICENSE-2.0 | |||
* | |||
* Unless required by applicable law or agreed to in writing, software | |||
* distributed under the License is distributed on an "AS IS" BASIS, | |||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
* See the License for the specific language governing permissions and | |||
* limitations under the License. | |||
*/ | |||
package compressor | |||
type Compressor interface { | |||
Compress([]byte) ([]byte, error) | |||
Decompress([]byte) ([]byte, error) | |||
GetCompressorType() CompressorType | |||
} |
@@ -1,53 +0,0 @@ | |||
/* | |||
* Licensed to the Apache Software Foundation (ASF) under one or more | |||
* contributor license agreements. See the NOTICE file distributed with | |||
* this work for additional information regarding copyright ownership. | |||
* The ASF licenses this file to You under the Apache License, Version 2.0 | |||
* (the "License"); you may not use this file except in compliance with | |||
* the License. You may obtain a copy of the License at | |||
* | |||
* http://www.apache.org/licenses/LICENSE-2.0 | |||
* | |||
* Unless required by applicable law or agreed to in writing, software | |||
* distributed under the License is distributed on an "AS IS" BASIS, | |||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
* See the License for the specific language governing permissions and | |||
* limitations under the License. | |||
*/ | |||
package compressor | |||
type CompressorType string | |||
const ( | |||
// "None" means no compressor is used | |||
CompressorNone CompressorType = "None" | |||
CompressorGzip CompressorType = "Gzip" | |||
CompressorZip CompressorType = "Zip" | |||
CompressorSevenz CompressorType = "Sevenz" | |||
CompressorBzip2 CompressorType = "Bzip2" | |||
CompressorLz4 CompressorType = "Lz4" | |||
CompressorDeflate CompressorType = "Deflate" | |||
CompressorZstd CompressorType = "Zstd" | |||
) | |||
func (c CompressorType) GetCompressor() Compressor { | |||
switch c { | |||
case CompressorNone: | |||
return &NoneCompressor{} | |||
case CompressorGzip: | |||
return &Gzip{} | |||
case CompressorZip: | |||
return &Zip{} | |||
case CompressorBzip2: | |||
return &Bzip2{} | |||
case CompressorLz4: | |||
return &Lz4{} | |||
case CompressorZstd: | |||
return &Zstd{} | |||
case CompressorDeflate: | |||
return &DeflateCompress{} | |||
default: | |||
return &NoneCompressor{} | |||
} | |||
} |
@@ -1,51 +0,0 @@ | |||
/* | |||
* Licensed to the Apache Software Foundation (ASF) under one or more | |||
* contributor license agreements. See the NOTICE file distributed with | |||
* this work for additional information regarding copyright ownership. | |||
* The ASF licenses this file to You under the Apache License, Version 2.0 | |||
* (the "License"); you may not use this file except in compliance with | |||
* the License. You may obtain a copy of the License at | |||
* | |||
* http://www.apache.org/licenses/LICENSE-2.0 | |||
* | |||
* Unless required by applicable law or agreed to in writing, software | |||
* distributed under the License is distributed on an "AS IS" BASIS, | |||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
* See the License for the specific language governing permissions and | |||
* limitations under the License. | |||
*/ | |||
package compressor | |||
import ( | |||
"bytes" | |||
"compress/flate" | |||
"io" | |||
"seata.apache.org/seata-go/pkg/util/log" | |||
) | |||
type DeflateCompress struct{} | |||
func (*DeflateCompress) Compress(data []byte) ([]byte, error) { | |||
var buf bytes.Buffer | |||
fw, err := flate.NewWriter(&buf, flate.BestCompression) | |||
if err != nil { | |||
log.Error(err) | |||
return nil, err | |||
} | |||
defer fw.Close() | |||
fw.Write(data) | |||
fw.Flush() | |||
return buf.Bytes(), nil | |||
} | |||
func (*DeflateCompress) Decompress(data []byte) ([]byte, error) { | |||
fr := flate.NewReader(bytes.NewBuffer(data)) | |||
defer fr.Close() | |||
return io.ReadAll(fr) | |||
} | |||
func (*DeflateCompress) GetCompressorType() CompressorType { | |||
return CompressorDeflate | |||
} |
@@ -1,53 +0,0 @@ | |||
/* | |||
* Licensed to the Apache Software Foundation (ASF) under one or more | |||
* contributor license agreements. See the NOTICE file distributed with | |||
* this work for additional information regarding copyright ownership. | |||
* The ASF licenses this file to You under the Apache License, Version 2.0 | |||
* (the "License"); you may not use this file except in compliance with | |||
* the License. You may obtain a copy of the License at | |||
* | |||
* http://www.apache.org/licenses/LICENSE-2.0 | |||
* | |||
* Unless required by applicable law or agreed to in writing, software | |||
* distributed under the License is distributed on an "AS IS" BASIS, | |||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
* See the License for the specific language governing permissions and | |||
* limitations under the License. | |||
*/ | |||
package compressor | |||
import ( | |||
"testing" | |||
"github.com/stretchr/testify/assert" | |||
) | |||
func TestDeflateCompress(t *testing.T) { | |||
ts := []struct { | |||
text string | |||
}{ | |||
{ | |||
text: "Don't communicate by sharing memory, share memory by communicating.", | |||
}, | |||
{ | |||
text: "Concurrency is not parallelism.", | |||
}, | |||
{ | |||
text: "The bigger the interface, the weaker the abstraction.", | |||
}, | |||
{ | |||
text: "Documentation is for users.", | |||
}, | |||
} | |||
dc := &DeflateCompress{} | |||
assert.EqualValues(t, CompressorDeflate, dc.GetCompressorType()) | |||
for _, s := range ts { | |||
var data []byte = []byte(s.text) | |||
dataCompressed, _ := dc.Compress(data) | |||
ret, _ := dc.Decompress(dataCompressed) | |||
assert.EqualValues(t, s.text, string(ret)) | |||
} | |||
} |
@@ -1,66 +0,0 @@ | |||
/* | |||
* Licensed to the Apache Software Foundation (ASF) under one or more | |||
* contributor license agreements. See the NOTICE file distributed with | |||
* this work for additional information regarding copyright ownership. | |||
* The ASF licenses this file to You under the Apache License, Version 2.0 | |||
* (the "License"); you may not use this file except in compliance with | |||
* the License. You may obtain a copy of the License at | |||
* | |||
* http://www.apache.org/licenses/LICENSE-2.0 | |||
* | |||
* Unless required by applicable law or agreed to in writing, software | |||
* distributed under the License is distributed on an "AS IS" BASIS, | |||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
* See the License for the specific language governing permissions and | |||
* limitations under the License. | |||
*/ | |||
package compressor | |||
import ( | |||
"bytes" | |||
"compress/gzip" | |||
"io/ioutil" | |||
) | |||
type Gzip struct { | |||
} | |||
// Compress gzip compress | |||
func (g *Gzip) Compress(b []byte) ([]byte, error) { | |||
var buffer bytes.Buffer | |||
gz := gzip.NewWriter(&buffer) | |||
if _, err := gz.Write(b); err != nil { | |||
return nil, err | |||
} | |||
if err := gz.Flush(); err != nil { | |||
return nil, err | |||
} | |||
if err := gz.Close(); err != nil { | |||
return nil, err | |||
} | |||
return buffer.Bytes(), nil | |||
} | |||
// Decompress gzip decompress | |||
func (g *Gzip) Decompress(in []byte) ([]byte, error) { | |||
reader, err := gzip.NewReader(bytes.NewReader(in)) | |||
if err != nil { | |||
return nil, err | |||
} | |||
if err = reader.Close(); err != nil { | |||
return nil, err | |||
} | |||
return ioutil.ReadAll(reader) | |||
} | |||
func (g *Gzip) GetCompressorType() CompressorType { | |||
return CompressorGzip | |||
} |
@@ -1,40 +0,0 @@ | |||
/* | |||
* Licensed to the Apache Software Foundation (ASF) under one or more | |||
* contributor license agreements. See the NOTICE file distributed with | |||
* this work for additional information regarding copyright ownership. | |||
* The ASF licenses this file to You under the Apache License, Version 2.0 | |||
* (the "License"); you may not use this file except in compliance with | |||
* the License. You may obtain a copy of the License at | |||
* | |||
* http://www.apache.org/licenses/LICENSE-2.0 | |||
* | |||
* Unless required by applicable law or agreed to in writing, software | |||
* distributed under the License is distributed on an "AS IS" BASIS, | |||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
* See the License for the specific language governing permissions and | |||
* limitations under the License. | |||
*/ | |||
package compressor | |||
import ( | |||
"testing" | |||
"github.com/stretchr/testify/assert" | |||
) | |||
func TestGzipCompress(t *testing.T) { | |||
str := "test" | |||
g := &Gzip{} | |||
compressRes, err := g.Compress([]byte(str)) | |||
assert.NoError(t, err) | |||
t.Logf("compress res: %v", string(compressRes)) | |||
decompressRes, err := g.Decompress(compressRes) | |||
assert.NoError(t, err) | |||
t.Logf("decompress res: %v", string(decompressRes)) | |||
assert.Equal(t, str, string(decompressRes)) | |||
} |