diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index b698e42..2edc31e 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -9,8 +9,14 @@ jobs:
name: Release on GitHub
runs-on: ubuntu-latest
steps:
+ - name: Get Release Version
+ run: |
+ export RELEASE_VERSION=${GITHUB_REF#refs/*/}
+ echo RELEASE_VERSION: ${RELEASE_VERSION}
+ echo "RELEASE_VERSION=${RELEASE_VERSION}" >> $GITHUB_ENV
+
- name: Check out code
- uses: actions/checkout@v2
+ uses: actions/checkout@v3
- name: Validates GO releaser config
uses: docker://goreleaser/goreleaser:v1.7.0
@@ -24,7 +30,38 @@ jobs:
env:
GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}
- - name: Docker meta
+ - name: Setup node
+ uses: actions/setup-node@v3
+ with:
+ node-version: 14
+
+ - name: Build admin
+ run: |
+ cd admin
+ npm install -g yarn
+ yarn
+ VITE_ADMIN_VERSION=${{ env.RELEASE_VERSION }} yarn build
+ cd ..
+
+ - name: Scp admin
+ env:
+ host: 'ubuntu@en.dtm.pub'
+ host2: 'ubuntu@dtm.pub'
+ dest: '/data/dtm-admin/'
+ run: |
+ cd admin
+ echo "${{secrets.DEPLOY_KEY}}" > deploy_key
+ chmod 600 ./deploy_key
+ tar -cvzf dist.tar.gz dist
+ scp -i deploy_key -o StrictHostKeyChecking=no dist.tar.gz ${{env.host}}:${{env.dest}}
+ ssh -i deploy_key -o StrictHostKeyChecking=no ${{env.host}} 'cd ${{env.dest}} && tar -zvxf dist.tar.gz'
+ scp -i deploy_key -o StrictHostKeyChecking=no dist.tar.gz ${{env.host2}}:${{env.dest}}
+ ssh -i deploy_key -o StrictHostKeyChecking=no ${{env.host2}} 'cd ${{env.dest}} && tar -zvxf dist.tar.gz'
+ rm deploy_key dist.tar.gz
+ echo > dist/placeholder
+ cd ..
+
+ - name: Create Docker
id: meta
uses: docker/metadata-action@v3
with:
@@ -48,9 +85,6 @@ jobs:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- - name: Get Release Version
- run: echo "RELEASE_VERSION=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV
-
- name: Build and push
uses: docker/build-push-action@v2
with:
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index e71699d..d12fe2a 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -28,6 +28,16 @@ jobs:
- /etc/timezone:/etc/timezone:ro
ports:
- 6379:6379
+ postgres:
+ image: 'yedf/postgres-xa'
+ volumes:
+ - /etc/localtime:/etc/localtime:ro
+ - /etc/timezone:/etc/timezone:ro
+ env:
+ POSTGRES_PASSWORD: mysecretpassword
+ POSTGRES_DB: dtm
+ ports:
+ - '5432:5432'
mongo:
image: 'yedf/mongo-rs'
volumes:
diff --git a/.gitignore b/.gitignore
index f0476cb..135fe3c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,7 +1,7 @@
conf.yml
*.out
*.log
-dist
+# dist
.idea/**
.vscode
default.etcd
diff --git a/README.md b/README.md
index 5e49007..1c7e181 100644
--- a/README.md
+++ b/README.md
@@ -15,13 +15,17 @@ DTM is a distributed transaction framework which provides cross-service eventual
+## Features
+
## Who's using DTM (partial)
-[Tencent](https://www.tencent.com/)
+[Tencent](https://en.dtm.pub/other/using.html#tencent)
+
+[Bytedance](https://en.dtm.pub/other/using.html#bytedance)
-[Bytedance](https://www.bytedance.com/)
+[Ivydad](https://en.dtm.pub/other/using.html#ivydad)
-[Ivydad](https://ivydad.com)
+[More](https://en.dtm.pub/other/using.html)
## [Cook Book](https://en.dtm.pub)
@@ -54,7 +58,7 @@ go run main.go
DtmServer := "http://localhost:36789/api/dtmsvr"
req := &gin.H{"amount": 30} // micro-service payload
// DtmServer is the address of DTM micro-service
- saga := dtmcli.NewSaga(DtmServer, dtmcli.MustGenGid(DtmServer)).
+ saga := dtmcli.NewSaga(DtmServer, shortuuid.New()).
// add a TransOut subtraction,forward operation with url: qsBusi+"/TransOut", reverse compensation operation with url: qsBusi+"/TransOutCom"
Add(qsBusi+"/TransOut", qsBusi+"/TransOutCom", req).
// add a TransIn subtraction, forward operation with url: qsBusi+"/TransIn", reverse compensation operation with url: qsBusi+"/TransInCom"
diff --git a/admin/.env b/admin/.env
new file mode 100644
index 0000000..fde6533
--- /dev/null
+++ b/admin/.env
@@ -0,0 +1 @@
+VITE_ADMIN_VERSION="v0.0.0-dev"
diff --git a/dashboard/.eslintrc.js b/admin/.eslintrc.js
similarity index 100%
rename from dashboard/.eslintrc.js
rename to admin/.eslintrc.js
diff --git a/dashboard/.gitignore b/admin/.gitignore
similarity index 100%
rename from dashboard/.gitignore
rename to admin/.gitignore
diff --git a/dashboard/README.md b/admin/README.md
similarity index 100%
rename from dashboard/README.md
rename to admin/README.md
diff --git a/admin/dist/placeholder b/admin/dist/placeholder
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/admin/dist/placeholder
@@ -0,0 +1 @@
+
diff --git a/dashboard/index.html b/admin/index.html
similarity index 100%
rename from dashboard/index.html
rename to admin/index.html
diff --git a/dashboard/package.json b/admin/package.json
similarity index 92%
rename from dashboard/package.json
rename to admin/package.json
index 8be934b..e5101f4 100644
--- a/dashboard/package.json
+++ b/admin/package.json
@@ -4,7 +4,7 @@
"version": "0.0.0",
"scripts": {
"dev": "vite",
- "build": "vite build",
+ "build": "vite build && echo > dist/placeholder",
"preview": "vite preview"
},
"dependencies": {
@@ -28,6 +28,7 @@
"postcss-import": "^14.1.0",
"postcss-nested": "^5.0.6",
"postcss-simple-vars": "^6.0.3",
+ "screenfull": "^6.0.1",
"tailwindcss": "^3.0.24",
"typescript": "^4.5.4",
"unplugin-vue-components": "^0.19.3",
diff --git a/dashboard/postcss.config.js b/admin/postcss.config.js
similarity index 100%
rename from dashboard/postcss.config.js
rename to admin/postcss.config.js
diff --git a/dashboard/public/favicon.ico b/admin/public/favicon.ico
similarity index 100%
rename from dashboard/public/favicon.ico
rename to admin/public/favicon.ico
diff --git a/dashboard/src/App.vue b/admin/src/App.vue
similarity index 100%
rename from dashboard/src/App.vue
rename to admin/src/App.vue
diff --git a/admin/src/api/api_dtm.ts b/admin/src/api/api_dtm.ts
new file mode 100644
index 0000000..20f368a
--- /dev/null
+++ b/admin/src/api/api_dtm.ts
@@ -0,0 +1,38 @@
+import { AxiosResponse } from 'axios'
+import request from '/@/utils/request'
+
+export interface IListAllTransactionsReq {
+ limit: number
+ position?: string
+}
+
+export function listAllTransactions(payload: IListAllTransactionsReq): Promise> {
+ return request({
+ url: '/api/dtmsvr/all',
+ method: 'get',
+ params: payload
+ })
+}
+
+export function forceStopTransaction(gid: string): Promise {
+ return request({
+ url: '/api/dtmsvr/forceStop',
+ method: 'post',
+ data: { gid },
+ })
+}
+
+export function getTransaction(payload: { gid: string }): Promise> {
+ return request({
+ url: '/api/dtmsvr/query',
+ method: 'get',
+ params: payload
+ })
+}
+
+export function getDtmVersion(): Promise> {
+ return request({
+ url: '/api/dtmsvr/version',
+ method: 'get',
+ })
+}
diff --git a/dashboard/src/assets/css/index.css b/admin/src/assets/css/index.css
similarity index 100%
rename from dashboard/src/assets/css/index.css
rename to admin/src/assets/css/index.css
diff --git a/dashboard/src/components.d.ts b/admin/src/components.d.ts
similarity index 82%
rename from dashboard/src/components.d.ts
rename to admin/src/components.d.ts
index 1c6807f..eb0b33b 100644
--- a/dashboard/src/components.d.ts
+++ b/admin/src/components.d.ts
@@ -5,6 +5,7 @@ import '@vue/runtime-core'
declare module '@vue/runtime-core' {
export interface GlobalComponents {
+ AAlert: typeof import('ant-design-vue/es')['Alert']
ABreadcrumb: typeof import('ant-design-vue/es')['Breadcrumb']
ABreadcrumbItem: typeof import('ant-design-vue/es')['BreadcrumbItem']
AButton: typeof import('ant-design-vue/es')['Button']
@@ -14,11 +15,14 @@ declare module '@vue/runtime-core' {
ALayoutSider: typeof import('ant-design-vue/es')['LayoutSider']
AMenu: typeof import('ant-design-vue/es')['Menu']
AMenuItem: typeof import('ant-design-vue/es')['MenuItem']
+ AModal: typeof import('ant-design-vue/es')['Modal']
ASubMenu: typeof import('ant-design-vue/es')['SubMenu']
ATable: typeof import('ant-design-vue/es')['Table']
ATag: typeof import('ant-design-vue/es')['Tag']
+ ATextarea: typeof import('ant-design-vue/es')['Textarea']
RouterLink: typeof import('vue-router')['RouterLink']
RouterView: typeof import('vue-router')['RouterView']
+ Screenfull: typeof import('./components/Screenfull/index.vue')['default']
SvgIcon: typeof import('./components/SvgIcon/index.vue')['default']
}
}
diff --git a/admin/src/components/Screenfull/index.vue b/admin/src/components/Screenfull/index.vue
new file mode 100644
index 0000000..6f12919
--- /dev/null
+++ b/admin/src/components/Screenfull/index.vue
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
diff --git a/dashboard/src/components/SvgIcon/index.vue b/admin/src/components/SvgIcon/index.vue
similarity index 96%
rename from dashboard/src/components/SvgIcon/index.vue
rename to admin/src/components/SvgIcon/index.vue
index f6fd3a5..29bd947 100644
--- a/dashboard/src/components/SvgIcon/index.vue
+++ b/admin/src/components/SvgIcon/index.vue
@@ -30,6 +30,8 @@ const styleExternalIcon = () => {
diff --git a/dashboard/src/layout/components/sidebar.vue b/admin/src/layout/components/sidebar.vue
similarity index 100%
rename from dashboard/src/layout/components/sidebar.vue
rename to admin/src/layout/components/sidebar.vue
diff --git a/dashboard/src/layout/index.vue b/admin/src/layout/index.vue
similarity index 100%
rename from dashboard/src/layout/index.vue
rename to admin/src/layout/index.vue
diff --git a/admin/src/main.ts b/admin/src/main.ts
new file mode 100644
index 0000000..26dffc7
--- /dev/null
+++ b/admin/src/main.ts
@@ -0,0 +1,33 @@
+import { createApp } from 'vue'
+import App from './App.vue'
+import router from '/@/router/index'
+import { pinia } from '/@/store'
+import { useLayoutStore } from '/@/store/modules/layout'
+import '/@/permission'
+
+import '/@/assets/css/index.css'
+import 'virtual:svg-icons-register'
+
+const app = createApp(App)
+app.use(router)
+app.use(pinia)
+app.mount('#app')
+
+
+window.onunhandledrejection = (ev: PromiseRejectionEvent) => {
+ showAlert(ev.reason.stack || ev.reason.message)
+
+}
+window.onerror = err => {
+ if (typeof err === "string") {
+ return showAlert(err)
+ }
+ showAlert(JSON.stringify(err))
+}
+
+function showAlert(msg: string) {
+ let layout = useLayoutStore()
+ if (!layout.globalError) {
+ layout.setGlobalError(msg)
+ }
+}
\ No newline at end of file
diff --git a/dashboard/src/permission.ts b/admin/src/permission.ts
similarity index 100%
rename from dashboard/src/permission.ts
rename to admin/src/permission.ts
diff --git a/dashboard/src/router/asyncRouter.ts b/admin/src/router/asyncRouter.ts
similarity index 100%
rename from dashboard/src/router/asyncRouter.ts
rename to admin/src/router/asyncRouter.ts
diff --git a/admin/src/router/index.ts b/admin/src/router/index.ts
new file mode 100644
index 0000000..dbc0371
--- /dev/null
+++ b/admin/src/router/index.ts
@@ -0,0 +1,59 @@
+import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router'
+import { IMenubarList } from '../type/store/layout';
+import { components } from './asyncRouter';
+
+const Components: IObject<() => Promise> = Object.assign({}, components, {
+ LayoutHeader: (() => import('/@/layout/index.vue')) as unknown as () => Promise,
+ LayoutMain: (() => import('/@/layout/aside.vue')) as unknown as () => Promise
+})
+
+export const allowRouter: Array = [
+ {
+ name: 'Admin',
+ path: '/',
+ redirect: '/admin/global-transactions/all',
+ component: Components['LayoutHeader'],
+ meta: { title: 'Admin', activeMenu: '/admin' },
+ children: [
+ {
+ // name: 'Nodes',
+ // path: '/admin/nodes',
+ // component: Components['LayoutMain'],
+ // meta: { title: 'Nodes' },
+ // children: [
+ // {
+ // name: 'LivingNodes',
+ // path: '/admin/nodes/living',
+ // component: Components['LivingNodes'],
+ // meta: { title: 'Living Nodes' },
+ // }
+ // ]
+ // }, {
+ name: 'GlobalTransactions',
+ path: '/admin/global-transactions',
+ component: Components['LayoutMain'],
+ meta: { title: 'Global Transactions' },
+ children: [
+ {
+ name: 'AllTransactions',
+ path: '/admin/global-transactions/all',
+ component: Components['AllTransactions'],
+ meta: { title: 'All Transactions' },
+ // }, {
+ // name: 'UnfinishedTransactions',
+ // path: '/admin/global-transactions/unfinished',
+ // component: Components['UnfinishedTransactions'],
+ // meta: { title: 'Unfinished Transactions' },
+ }
+ ]
+ }
+ ]
+ }
+]
+
+const router = createRouter({
+ history: createWebHistory(),
+ routes: allowRouter as RouteRecordRaw[]
+})
+
+export default router
diff --git a/dashboard/src/store/index.ts b/admin/src/store/index.ts
similarity index 100%
rename from dashboard/src/store/index.ts
rename to admin/src/store/index.ts
diff --git a/dashboard/src/store/modules/layout.ts b/admin/src/store/modules/layout.ts
similarity index 64%
rename from dashboard/src/store/modules/layout.ts
rename to admin/src/store/modules/layout.ts
index 135fa36..0e2d8a5 100644
--- a/dashboard/src/store/modules/layout.ts
+++ b/admin/src/store/modules/layout.ts
@@ -1,17 +1,19 @@
import { defineStore } from 'pinia';
import { allowRouter } from '/@/router';
import { ILayout, IMenubar, IMenubarList, IStatus } from '/@/type/store/layout';
-import { findCurrentMenubar } from '/@/utils/util';
+import { getDtmVersion } from '/@/api/api_dtm';
export const useLayoutStore = defineStore({
id: 'layout',
- state: ():ILayout => ({
+ state: (): ILayout => ({
menubar: {
menuList: []
},
status: {
isLoading: false
},
+ dtmVersion: "",
+ globalError: "",
}),
getters: {
getMenubar(): IMenubar {
@@ -25,8 +27,16 @@ export const useLayoutStore = defineStore({
setRoutes(data: Array): void {
this.menubar.menuList = data
},
+ setGlobalError(err: string) {
+ this.globalError = err
+ },
concatAllowRoutes(): void {
allowRouter.reverse().forEach(v => this.menubar.menuList.unshift(v))
},
+ async loadDtmVersion(): Promise {
+ const { data: { version } } = await getDtmVersion()
+ this.dtmVersion = version
+ console.log("dtm version: ", this.dtmVersion)
+ }
}
})
diff --git a/dashboard/src/type/index.d.ts b/admin/src/type/index.d.ts
similarity index 66%
rename from dashboard/src/type/index.d.ts
rename to admin/src/type/index.d.ts
index 8ac4521..53b355b 100644
--- a/dashboard/src/type/index.d.ts
+++ b/admin/src/type/index.d.ts
@@ -1,4 +1,4 @@
-export {}
+export { }
declare global {
interface IObject {
[index: string]: T
@@ -7,10 +7,11 @@ declare global {
VITE_APP_TITLE: string
VITE_PORT: number
VITE_PROXY: string
+ VITE_ADMIN_VERSION: string
}
interface ITable {
- data: Array
- next_position: number,
- size: number
+ data: Array
+ next_position: number,
+ size: number
}
}
diff --git a/dashboard/src/type/shim.vue.d.ts b/admin/src/type/shim.vue.d.ts
similarity index 100%
rename from dashboard/src/type/shim.vue.d.ts
rename to admin/src/type/shim.vue.d.ts
diff --git a/dashboard/src/type/store/layout.ts b/admin/src/type/store/layout.ts
similarity index 74%
rename from dashboard/src/type/store/layout.ts
rename to admin/src/type/store/layout.ts
index a7121bd..e2f7ea7 100644
--- a/dashboard/src/type/store/layout.ts
+++ b/admin/src/type/store/layout.ts
@@ -1,14 +1,16 @@
export interface IMenubar {
- menuList: Array
+ menuList: Array
}
export interface ILayout {
- menubar: IMenubar
- status: IStatus
+ menubar: IMenubar
+ status: IStatus
+ dtmVersion: string
+ globalError: string
}
export interface IStatus {
- isLoading: boolean
+ isLoading: boolean
}
export interface IMenubarList {
@@ -16,7 +18,7 @@ export interface IMenubarList {
id?: number | string
name: string
path: string
- redirect?: string
+ redirect?: string
meta: {
icon?: string
title: string
diff --git a/dashboard/src/utils/request.ts b/admin/src/utils/request.ts
similarity index 58%
rename from dashboard/src/utils/request.ts
rename to admin/src/utils/request.ts
index 09b32db..1ce371f 100644
--- a/dashboard/src/utils/request.ts
+++ b/admin/src/utils/request.ts
@@ -1,7 +1,6 @@
import axios from 'axios'
const request = axios.create({
- baseURL: import.meta.env.VITE_APP_API_BASE_URL as string | undefined,
timeout: 60000
})
diff --git a/dashboard/src/utils/util.ts b/admin/src/utils/util.ts
similarity index 79%
rename from dashboard/src/utils/util.ts
rename to admin/src/utils/util.ts
index 43dc575..1f2b118 100644
--- a/dashboard/src/utils/util.ts
+++ b/admin/src/utils/util.ts
@@ -1,9 +1,9 @@
import { useRoute } from 'vue-router';
import { IMenubarList } from '../type/store/layout';
-export const findCurrentMenubar = (menuList: IMenubarList[], root?:boolean) => {
+export const findCurrentMenubar = (menuList: IMenubarList[], root?: boolean) => {
const route = useRoute()
- let arr:IMenubarList[] | IMenubarList = []
+ let arr: IMenubarList[] | IMenubarList = []
for (let i = 0; i < menuList.length; i++) {
const v = menuList[i];
const usePath = v.meta.activeMenu || v.redirect || v.path;
@@ -21,3 +21,7 @@ export const findCurrentMenubar = (menuList: IMenubarList[], root?:boolean) => {
return arr
}
+
+export const sleep = async (ms: number) => {
+ return new Promise(resolve => setTimeout(resolve, ms))
+}
\ No newline at end of file
diff --git a/dashboard/src/views/Dashboard/GlobalTransactions/AllTransactions.vue b/admin/src/views/Dashboard/GlobalTransactions/AllTransactions.vue
similarity index 61%
rename from dashboard/src/views/Dashboard/GlobalTransactions/AllTransactions.vue
rename to admin/src/views/Dashboard/GlobalTransactions/AllTransactions.vue
index 7f70c4d..e57924d 100644
--- a/dashboard/src/views/Dashboard/GlobalTransactions/AllTransactions.vue
+++ b/admin/src/views/Dashboard/GlobalTransactions/AllTransactions.vue
@@ -4,13 +4,14 @@
- {{ record.status.toUpperCase() }}
+ {{ record.status }}
- Detail
- Stop
+ Detail
+ ForceStop
+
@@ -19,13 +20,15 @@
Previous
Next
+
+
diff --git a/dashboard/src/views/Dashboard/Nodes/LivingNodes.vue b/admin/src/views/Dashboard/Nodes/LivingNodes.vue
similarity index 100%
rename from dashboard/src/views/Dashboard/Nodes/LivingNodes.vue
rename to admin/src/views/Dashboard/Nodes/LivingNodes.vue
diff --git a/dashboard/tailwind.config.js b/admin/tailwind.config.js
similarity index 100%
rename from dashboard/tailwind.config.js
rename to admin/tailwind.config.js
diff --git a/dashboard/tsconfig.json b/admin/tsconfig.json
similarity index 100%
rename from dashboard/tsconfig.json
rename to admin/tsconfig.json
diff --git a/dashboard/vite.config.ts b/admin/vite.config.ts
similarity index 96%
rename from dashboard/vite.config.ts
rename to admin/vite.config.ts
index 18e1f84..df61c87 100644
--- a/dashboard/vite.config.ts
+++ b/admin/vite.config.ts
@@ -28,8 +28,8 @@ export default ({ }: ConfigEnv): UserConfigExport => {
})
],
server: {
- port: 5000,
- base: 'dashboard',
+ port: 6789,
+ base: 'admin',
proxy: {
'/api': {
target: 'http://localhost:36789',
diff --git a/dashboard/yarn.lock b/admin/yarn.lock
similarity index 99%
rename from dashboard/yarn.lock
rename to admin/yarn.lock
index 76a90b5..6458aac 100644
--- a/dashboard/yarn.lock
+++ b/admin/yarn.lock
@@ -2681,6 +2681,11 @@ safe-regex@^1.1.0:
dependencies:
ret "~0.1.10"
+screenfull@^6.0.1:
+ version "6.0.1"
+ resolved "https://registry.npmmirror.com/screenfull/-/screenfull-6.0.1.tgz#3b71e6f06b72d817a8d3be73c45ebe71fa8da1ce"
+ integrity sha512-yzQW+j4zMUBQC51xxWaoDYjxOtl8Kn+xvue3p6v/fv2pIi1jH4AldgVLU8TBfFVgH2x3VXlf3+YiA/AYIPlaew==
+
scroll-into-view-if-needed@^2.2.25:
version "2.2.29"
resolved "https://registry.npmmirror.com/scroll-into-view-if-needed/-/scroll-into-view-if-needed-2.2.29.tgz"
diff --git a/conf.sample.yml b/conf.sample.yml
index 1427da2..a256a2a 100644
--- a/conf.sample.yml
+++ b/conf.sample.yml
@@ -11,6 +11,7 @@
# User: 'root'
# Password: ''
# Port: 3306
+# Db: 'dtm'
# Driver: 'boltdb' # default store engine
@@ -30,8 +31,6 @@
# MaxOpenConns: 500
# MaxIdleConns: 500
# ConnMaxLifeTime: 5 # default value is 5 (minutes)
-# TransGlobalTable: 'dtm.trans_global'
-# TransBranchOpTable: 'dtm.trans_branch_op'
### flollowing config is only for some Driver
# DataExpire: 604800 # Trans data will expire in 7 days. only for redis/boltdb.
diff --git a/dashboard/.env.development b/dashboard/.env.development
deleted file mode 100644
index 88c4eb8..0000000
--- a/dashboard/.env.development
+++ /dev/null
@@ -1,2 +0,0 @@
-VITE_APP_API_BASE_URL="/api"
-VITE_PROXY=[["/api", "http://localhost:36789"]]
diff --git a/dashboard/src/layout/components/content.vue b/dashboard/src/layout/components/content.vue
deleted file mode 100644
index 0f8ba74..0000000
--- a/dashboard/src/layout/components/content.vue
+++ /dev/null
@@ -1,17 +0,0 @@
-
-
-
-
-
-
-
-
-
-
diff --git a/dashboard/src/main.ts b/dashboard/src/main.ts
deleted file mode 100644
index 34a4d4f..0000000
--- a/dashboard/src/main.ts
+++ /dev/null
@@ -1,13 +0,0 @@
-import { createApp } from 'vue'
-import App from './App.vue'
-import router from '/@/router/index'
-import { pinia } from '/@/store'
-import '/@/permission'
-
-import '/@/assets/css/index.css'
-import 'virtual:svg-icons-register'
-
-const app = createApp(App)
-app.use(router)
-app.use(pinia)
-app.mount('#app')
diff --git a/dashboard/src/router/index.ts b/dashboard/src/router/index.ts
deleted file mode 100644
index ee53971..0000000
--- a/dashboard/src/router/index.ts
+++ /dev/null
@@ -1,59 +0,0 @@
-import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router'
-import { IMenubarList } from '../type/store/layout';
-import { components } from './asyncRouter';
-
-const Components: IObject<() => Promise> = Object.assign({}, components, {
- LayoutHeader: (() => import('/@/layout/index.vue')) as unknown as () => Promise,
- LayoutMain: (() => import('/@/layout/aside.vue')) as unknown as () => Promise
-})
-
-export const allowRouter: Array = [
- {
- name: 'Dashboard',
- path: '/',
- redirect: '/dashboard/nodes/living',
- component: Components['LayoutHeader'],
- meta: { title: 'Dashboard', activeMenu: '/dashboard' },
- children: [
- {
- name: 'Nodes',
- path: '/dashboard/nodes',
- component: Components['LayoutMain'],
- meta: { title: 'Nodes' },
- children: [
- {
- name: 'LivingNodes',
- path: '/dashboard/nodes/living',
- component: Components['LivingNodes'],
- meta: { title: 'Living Nodes' },
- }
- ]
- }, {
- name: 'GlobalTransactions',
- path: '/dashboard/global-transactions',
- component: Components['LayoutMain'],
- meta: { title: 'Global Transactions' },
- children: [
- {
- name: 'AllTransactions',
- path: '/dashboard/global-transactions/all',
- component: Components['AllTransactions'],
- meta: { title: 'All Transactions' },
- }, {
- name: 'UnfinishedTransactions',
- path: '/dashboard/global-transactions/unfinished',
- component: Components['UnfinishedTransactions'],
- meta: { title: 'Unfinished Transactions' },
- }
- ]
- }
- ]
- }
-]
-
-const router = createRouter({
- history: createWebHistory(),
- routes: allowRouter as RouteRecordRaw[]
-})
-
-export default router
diff --git a/dtmcli/barrier.go b/dtmcli/barrier.go
index 1fcf61f..0b136cb 100644
--- a/dtmcli/barrier.go
+++ b/dtmcli/barrier.go
@@ -20,11 +20,13 @@ type BarrierBusiFunc func(tx *sql.Tx) error
// BranchBarrier every branch info
type BranchBarrier struct {
- TransType string
- Gid string
- BranchID string
- Op string
- BarrierID int
+ TransType string
+ Gid string
+ BranchID string
+ Op string
+ BarrierID int
+ DBType string // DBTypeMysql | DBTypePostgres
+ BarrierTableName string
}
func (bb *BranchBarrier) String() string {
@@ -70,8 +72,8 @@ func (bb *BranchBarrier) Call(tx *sql.Tx, busiCall BarrierBusiFunc) (rerr error)
dtmimp.OpCompensate: dtmimp.OpAction,
}[bb.Op]
- originAffected, oerr := dtmimp.InsertBarrier(tx, bb.TransType, bb.Gid, bb.BranchID, originOp, bid, bb.Op)
- currentAffected, rerr := dtmimp.InsertBarrier(tx, bb.TransType, bb.Gid, bb.BranchID, bb.Op, bid, bb.Op)
+ originAffected, oerr := dtmimp.InsertBarrier(tx, bb.TransType, bb.Gid, bb.BranchID, originOp, bid, bb.Op, bb.DBType, bb.BarrierTableName)
+ currentAffected, rerr := dtmimp.InsertBarrier(tx, bb.TransType, bb.Gid, bb.BranchID, bb.Op, bid, bb.Op, bb.DBType, bb.BarrierTableName)
logger.Debugf("originAffected: %d currentAffected: %d", originAffected, currentAffected)
if rerr == nil && bb.Op == dtmimp.MsgDoOp && currentAffected == 0 { // for msg's DoAndSubmit, repeated insert should be rejected.
@@ -103,10 +105,12 @@ func (bb *BranchBarrier) CallWithDB(db *sql.DB, busiCall BarrierBusiFunc) error
// QueryPrepared queries prepared data
func (bb *BranchBarrier) QueryPrepared(db *sql.DB) error {
- _, err := dtmimp.InsertBarrier(db, bb.TransType, bb.Gid, dtmimp.MsgDoBranch0, dtmimp.MsgDoOp, dtmimp.MsgDoBarrier1, dtmimp.OpRollback)
+ _, err := dtmimp.InsertBarrier(db, bb.TransType, bb.Gid, dtmimp.MsgDoBranch0, dtmimp.MsgDoOp, dtmimp.MsgDoBarrier1, dtmimp.OpRollback, bb.DBType, bb.BarrierTableName)
var reason string
if err == nil {
sql := fmt.Sprintf("select reason from %s where gid=? and branch_id=? and op=? and barrier_id=?", dtmimp.BarrierTableName)
+ sql = dtmimp.GetDBSpecial(bb.DBType).GetPlaceHoldSQL(sql)
+ logger.Debugf("queryrow: %s", sql, bb.Gid, dtmimp.MsgDoBranch0, dtmimp.MsgDoOp, dtmimp.MsgDoBarrier1)
err = db.QueryRow(sql, bb.Gid, dtmimp.MsgDoBranch0, dtmimp.MsgDoOp, dtmimp.MsgDoBarrier1).Scan(&reason)
}
if reason == dtmimp.OpRollback {
diff --git a/dtmcli/dtmimp/db_special.go b/dtmcli/dtmimp/db_special.go
index b4db7fc..2f20f17 100644
--- a/dtmcli/dtmimp/db_special.go
+++ b/dtmcli/dtmimp/db_special.go
@@ -75,8 +75,11 @@ func init() {
}
// GetDBSpecial get DBSpecial for currentDBType
-func GetDBSpecial() DBSpecial {
- return dbSpecials[currentDBType]
+func GetDBSpecial(dbType string) DBSpecial {
+ if dbType == "" {
+ dbType = currentDBType
+ }
+ return dbSpecials[dbType]
}
// SetCurrentDBType set currentDBType
diff --git a/dtmcli/dtmimp/db_special_test.go b/dtmcli/dtmimp/db_special_test.go
index 3966cd2..74632a1 100644
--- a/dtmcli/dtmimp/db_special_test.go
+++ b/dtmcli/dtmimp/db_special_test.go
@@ -18,13 +18,13 @@ func TestDBSpecial(t *testing.T) {
SetCurrentDBType("no-driver")
}))
SetCurrentDBType(DBTypeMysql)
- sp := GetDBSpecial()
+ sp := GetDBSpecial(DBTypeMysql)
assert.Equal(t, "? ?", sp.GetPlaceHoldSQL("? ?"))
assert.Equal(t, "xa start 'xa1'", sp.GetXaSQL("start", "xa1"))
assert.Equal(t, "insert ignore into a(f) values(?)", sp.GetInsertIgnoreTemplate("a(f) values(?)", "c"))
SetCurrentDBType(DBTypePostgres)
- sp = GetDBSpecial()
+ sp = GetDBSpecial(DBTypePostgres)
assert.Equal(t, "$1 $2", sp.GetPlaceHoldSQL("? ?"))
assert.Equal(t, "begin", sp.GetXaSQL("start", "xa1"))
assert.Equal(t, "insert into a(f) values(?) on conflict ON CONSTRAINT c do nothing", sp.GetInsertIgnoreTemplate("a(f) values(?)", "c"))
diff --git a/dtmcli/dtmimp/trans_xa_base.go b/dtmcli/dtmimp/trans_xa_base.go
index 50bb9c8..6eedb31 100644
--- a/dtmcli/dtmimp/trans_xa_base.go
+++ b/dtmcli/dtmimp/trans_xa_base.go
@@ -18,14 +18,14 @@ func XaHandlePhase2(gid string, dbConf DBConf, branchID string, op string) error
return err
}
xaID := gid + "-" + branchID
- _, err = DBExec(db, GetDBSpecial().GetXaSQL(op, xaID))
+ _, err = DBExec(dbConf.Driver, db, GetDBSpecial(dbConf.Driver).GetXaSQL(op, xaID))
if err != nil &&
(strings.Contains(err.Error(), "XAER_NOTA") || strings.Contains(err.Error(), "does not exist")) { // Repeat commit/rollback with the same id, report this error, ignore
err = nil
}
if op == OpRollback && err == nil {
// rollback insert a row after prepare. no-error means prepare has finished.
- _, err = InsertBarrier(db, "xa", gid, branchID, OpAction, XaBarrier1, op)
+ _, err = InsertBarrier(db, "xa", gid, branchID, OpAction, XaBarrier1, op, dbConf.Driver, "")
}
return err
}
@@ -39,20 +39,20 @@ func XaHandleLocalTrans(xa *TransBase, dbConf DBConf, cb func(*sql.DB) error) (r
}
defer func() { _ = db.Close() }()
defer DeferDo(&rerr, func() error {
- _, err := DBExec(db, GetDBSpecial().GetXaSQL("prepare", xaBranch))
+ _, err := DBExec(dbConf.Driver, db, GetDBSpecial(dbConf.Driver).GetXaSQL("prepare", xaBranch))
return err
}, func() error {
return nil
})
- _, rerr = DBExec(db, GetDBSpecial().GetXaSQL("start", xaBranch))
+ _, rerr = DBExec(dbConf.Driver, db, GetDBSpecial(dbConf.Driver).GetXaSQL("start", xaBranch))
if rerr != nil {
return
}
defer func() {
- _, _ = DBExec(db, GetDBSpecial().GetXaSQL("end", xaBranch))
+ _, _ = DBExec(dbConf.Driver, db, GetDBSpecial(dbConf.Driver).GetXaSQL("end", xaBranch))
}()
// prepare and rollback both insert a row
- _, rerr = InsertBarrier(db, xa.TransType, xa.Gid, xa.BranchID, OpAction, XaBarrier1, OpAction)
+ _, rerr = InsertBarrier(db, xa.TransType, xa.Gid, xa.BranchID, OpAction, XaBarrier1, OpAction, dbConf.Driver, "")
if rerr == nil {
rerr = cb(db)
}
diff --git a/dtmcli/dtmimp/utils.go b/dtmcli/dtmimp/utils.go
index 7220b30..1e5607a 100644
--- a/dtmcli/dtmimp/utils.go
+++ b/dtmcli/dtmimp/utils.go
@@ -187,12 +187,12 @@ func XaDB(conf DBConf) (*sql.DB, error) {
}
// DBExec use raw db to exec
-func DBExec(db DB, sql string, values ...interface{}) (affected int64, rerr error) {
+func DBExec(dbType string, db DB, sql string, values ...interface{}) (affected int64, rerr error) {
if sql == "" {
return 0, nil
}
began := time.Now()
- sql = GetDBSpecial().GetPlaceHoldSQL(sql)
+ sql = GetDBSpecial(dbType).GetPlaceHoldSQL(sql)
r, rerr := db.Exec(sql, values...)
used := time.Since(began) / time.Millisecond
if rerr == nil {
@@ -262,10 +262,16 @@ func EscapeGet(qs url.Values, key string) string {
}
// InsertBarrier insert a record to barrier
-func InsertBarrier(tx DB, transType string, gid string, branchID string, op string, barrierID string, reason string) (int64, error) {
+func InsertBarrier(tx DB, transType string, gid string, branchID string, op string, barrierID string, reason string, dbType string, barrierTableName string) (int64, error) {
if op == "" {
return 0, nil
}
- sql := GetDBSpecial().GetInsertIgnoreTemplate(BarrierTableName+"(trans_type, gid, branch_id, op, barrier_id, reason) values(?,?,?,?,?,?)", "uniq_barrier")
- return DBExec(tx, sql, transType, gid, branchID, op, barrierID, reason)
+ if dbType == "" {
+ dbType = currentDBType
+ }
+ if barrierTableName == "" {
+ barrierTableName = BarrierTableName
+ }
+ sql := GetDBSpecial(dbType).GetInsertIgnoreTemplate(barrierTableName+"(trans_type, gid, branch_id, op, barrier_id, reason) values(?,?,?,?,?,?)", "uniq_barrier")
+ return DBExec(dbType, tx, sql, transType, gid, branchID, op, barrierID, reason)
}
diff --git a/dtmgrpc/type.go b/dtmgrpc/type.go
index f92d830..14244e3 100644
--- a/dtmgrpc/type.go
+++ b/dtmgrpc/type.go
@@ -8,6 +8,7 @@ package dtmgrpc
import (
context "context"
+ "fmt"
"github.com/dtm-labs/dtm/dtmcli"
"github.com/dtm-labs/dtm/dtmcli/dtmimp"
@@ -38,7 +39,8 @@ func GrpcError2DtmError(err error) error {
if st.Message() == dtmcli.ResultOngoing {
return dtmcli.ErrOngoing
}
- return dtmcli.ErrFailure
+
+ return fmt.Errorf("%s. %w", st.Message(), dtmcli.ErrFailure)
} else if ok && st.Code() == codes.FailedPrecondition {
return dtmcli.ErrOngoing
}
diff --git a/dtmsvr/api.go b/dtmsvr/api.go
index 809d2ee..831884a 100644
--- a/dtmsvr/api.go
+++ b/dtmsvr/api.go
@@ -15,6 +15,9 @@ import (
"github.com/dtm-labs/dtm/dtmsvr/storage"
)
+// Version store the passin version for dtm server
+var Version = ""
+
func svcSubmit(t *TransGlobal) interface{} {
t.Status = dtmcli.StatusSubmitted
branches, err := t.saveNew()
diff --git a/dtmsvr/api_http.go b/dtmsvr/api_http.go
index 2ca1da0..19aa7c6 100644
--- a/dtmsvr/api_http.go
+++ b/dtmsvr/api_http.go
@@ -19,6 +19,9 @@ import (
)
func addRoute(engine *gin.Engine) {
+ engine.GET("/api/dtmsvr/version", dtmutil.WrapHandler2(func(c *gin.Context) interface{} {
+ return gin.H{"version": Version}
+ }))
engine.GET("/api/dtmsvr/newGid", dtmutil.WrapHandler2(newGid))
engine.POST("/api/dtmsvr/prepare", dtmutil.WrapHandler2(prepare))
engine.POST("/api/dtmsvr/submit", dtmutil.WrapHandler2(submit))
@@ -89,8 +92,7 @@ func all(c *gin.Context) interface{} {
return map[string]interface{}{"transactions": globals, "next_position": position}
}
-// resetCronTime rest nextCronTime
-// Prevent multiple backoff from causing NextCronTime to be too long
+// unfinished transactions need to be retried as soon as possible after business downtime is recovered
func resetCronTime(c *gin.Context) interface{} {
sTimeoutSecond := dtmimp.OrString(c.Query("timeout"), strconv.FormatInt(3*conf.TimeoutToFail, 10))
sLimit := dtmimp.OrString(c.Query("limit"), "100")
diff --git a/dtmsvr/config/config.go b/dtmsvr/config/config.go
index 0cb3aca..0ae4b41 100644
--- a/dtmsvr/config/config.go
+++ b/dtmsvr/config/config.go
@@ -6,7 +6,7 @@ import (
"github.com/dtm-labs/dtm/dtmcli"
"github.com/dtm-labs/dtm/dtmcli/logger"
- "gopkg.in/yaml.v2"
+ "gopkg.in/yaml.v3"
)
const (
@@ -53,14 +53,13 @@ type Store struct {
Port int64 `yaml:"Port"`
User string `yaml:"User"`
Password string `yaml:"Password"`
+ Db string `yaml:"Db" default:"dtm"`
MaxOpenConns int64 `yaml:"MaxOpenConns" default:"500"`
MaxIdleConns int64 `yaml:"MaxIdleConns" default:"500"`
ConnMaxLifeTime int64 `yaml:"ConnMaxLifeTime" default:"5"`
DataExpire int64 `yaml:"DataExpire" default:"604800"` // Trans data will expire in 7 days. only for redis/boltdb.
FinishedDataExpire int64 `yaml:"FinishedDataExpire" default:"86400"` // finished Trans data will expire in 1 days. only for redis.
RedisPrefix string `yaml:"RedisPrefix" default:"{a}"` // Redis storage prefix. store data to only one slot in cluster
- TransGlobalTable string `yaml:"TransGlobalTable" default:"dtm.trans_global"`
- TransBranchOpTable string `yaml:"TransBranchOpTable" default:"dtm.trans_branch_op"`
}
// IsDB checks config driver is mysql or postgres
@@ -76,10 +75,12 @@ func (s *Store) GetDBConf() dtmcli.DBConf {
Port: s.Port,
User: s.User,
Password: s.Password,
+ Db: s.Db,
}
}
-type configType struct {
+// Type is the type for the config of dtm server
+type Type struct {
Store Store `yaml:"Store"`
TransCronInterval int64 `yaml:"TransCronInterval" default:"3"`
TimeoutToFail int64 `yaml:"TimeoutToFail" default:"35"`
@@ -97,7 +98,7 @@ type configType struct {
}
// Config config
-var Config = configType{}
+var Config = Type{}
// MustLoadConfig load config from env and file
func MustLoadConfig(confFile string) {
@@ -105,7 +106,7 @@ func MustLoadConfig(confFile string) {
if confFile != "" {
cont, err := ioutil.ReadFile(confFile)
logger.FatalIfError(err)
- err = yaml.UnmarshalStrict(cont, &Config)
+ err = yaml.Unmarshal(cont, &Config)
logger.FatalIfError(err)
}
scont, err := json.MarshalIndent(&Config, "", " ")
diff --git a/dtmsvr/config/config_utils.go b/dtmsvr/config/config_utils.go
index f588eee..fa27cc7 100644
--- a/dtmsvr/config/config_utils.go
+++ b/dtmsvr/config/config_utils.go
@@ -58,7 +58,7 @@ func toUnderscoreUpper(key string) string {
return strings.ToUpper(s2)
}
-func checkConfig(conf *configType) error {
+func checkConfig(conf *Type) error {
if conf.RetryInterval < 10 {
return errors.New("RetryInterval should not be less than 10")
}
diff --git a/dtmsvr/entry/main.go b/dtmsvr/entry/main.go
index 4fcc717..14d1247 100644
--- a/dtmsvr/entry/main.go
+++ b/dtmsvr/entry/main.go
@@ -14,13 +14,6 @@ import (
"go.uber.org/automaxprocs/maxprocs"
)
-func ver(version *string) {
- if *version == "" {
- *version = "0.0.0-dev"
- }
- fmt.Printf("dtm version: %s\n", *version)
-}
-
func usage() {
cmd := filepath.Base(os.Args[0])
s := "Usage: %s [options]\n\n"
@@ -35,14 +28,18 @@ var isReset = flag.Bool("r", false, "Reset dtm server data.")
var confFile = flag.String("c", "", "Path to the server configuration file.")
// Main is the entry point of dtm server.
-func Main(version *string) *gin.Engine {
+func Main(version *string) (*gin.Engine, *config.Type) {
flag.Parse()
+ if *version == "" {
+ *version = "v0.0.0-dev"
+ }
+ dtmsvr.Version = *version
if flag.NArg() > 0 || *isHelp {
usage()
- return nil
+ return nil, nil
} else if *isVersion {
- ver(version)
- return nil
+ fmt.Printf("dtm version: %s\n", *version)
+ return nil, nil
}
logger.Infof("dtm version is: %s", *version)
config.MustLoadConfig(*confFile)
@@ -58,5 +55,5 @@ func Main(version *string) *gin.Engine {
registry.WaitStoreUp()
app := dtmsvr.StartSvr() // start dtmsvr api
go dtmsvr.CronExpiredTrans(-1) // start dtmsvr cron job
- return app
+ return app, &config.Config
}
diff --git a/dtmsvr/storage/boltdb/boltdb.go b/dtmsvr/storage/boltdb/boltdb.go
index b705a5b..eeedcaf 100644
--- a/dtmsvr/storage/boltdb/boltdb.go
+++ b/dtmsvr/storage/boltdb/boltdb.go
@@ -11,7 +11,6 @@ import (
"strings"
"time"
- "github.com/dtm-labs/dtm/dtmcli"
"github.com/dtm-labs/dtm/dtmcli/dtmimp"
"github.com/dtm-labs/dtm/dtmcli/logger"
"github.com/dtm-labs/dtm/dtmsvr/storage"
@@ -276,7 +275,7 @@ func (s *Store) ScanTransGlobalStores(position *string, limit int64) []storage.T
globals := []storage.TransGlobalStore{}
err := s.boltDb.View(func(t *bolt.Tx) error {
cursor := t.Bucket(bucketGlobal).Cursor()
- for k, v := cursor.First(); k != nil; k, v = cursor.Next() {
+ for k, v := cursor.Seek([]byte(*position)); k != nil; k, v = cursor.Next() {
if string(k) == *position {
continue
}
@@ -383,42 +382,42 @@ func (s *Store) TouchCronTime(global *storage.TransGlobalStore, nextCronInterval
// LockOneGlobalTrans finds GlobalTrans
func (s *Store) LockOneGlobalTrans(expireIn time.Duration) *storage.TransGlobalStore {
- var trans *storage.TransGlobalStore
+ var transo *storage.TransGlobalStore
min := fmt.Sprintf("%d", time.Now().Add(expireIn).Unix())
- next := time.Now().Add(time.Duration(s.retryInterval) * time.Second)
err := s.boltDb.Update(func(t *bolt.Tx) error {
cursor := t.Bucket(bucketIndex).Cursor()
toDelete := [][]byte{}
- for trans == nil || trans.Status == dtmcli.StatusSucceed || trans.Status == dtmcli.StatusFailed {
- k, v := cursor.First()
- if k == nil || string(k) > min {
- return storage.ErrNotFound
- }
- trans = tGetGlobal(t, string(v))
+ for k, v := cursor.First(); k != nil && string(k) <= min; k, v = cursor.Next() {
toDelete = append(toDelete, k)
+ trans := tGetGlobal(t, string(v))
+ if trans != nil && !trans.IsFinished() {
+ transo = trans
+ break
+ }
}
for _, k := range toDelete {
err := t.Bucket(bucketIndex).Delete(k)
dtmimp.E2P(err)
}
- trans.NextCronTime = &next
- tPutGlobal(t, trans)
- tPutIndex(t, next.Unix(), trans.Gid)
+ if transo != nil {
+ next := time.Now().Add(time.Duration(s.retryInterval) * time.Second)
+ transo.NextCronTime = &next
+ tPutGlobal(t, transo)
+ tPutIndex(t, next.Unix(), transo.Gid)
+
+ }
return nil
})
- if err == storage.ErrNotFound {
- return nil
- }
dtmimp.E2P(err)
- return trans
+ return transo
}
-// ResetCronTime rest nextCronTime
-// Prevent multiple backoff from causing NextCronTime to be too long
-func (s *Store) ResetCronTime(timeout time.Duration, limit int64) (succeedCount int64, hasRemaining bool, err error) {
+// ResetCronTime reset nextCronTime
+// unfinished transactions need to be retried as soon as possible after business downtime is recovered
+func (s *Store) ResetCronTime(after time.Duration, limit int64) (succeedCount int64, hasRemaining bool, err error) {
next := time.Now()
var trans *storage.TransGlobalStore
- min := fmt.Sprintf("%d", time.Now().Add(timeout).Unix())
+ min := fmt.Sprintf("%d", time.Now().Add(after).Unix())
err = s.boltDb.Update(func(t *bolt.Tx) error {
cursor := t.Bucket(bucketIndex).Cursor()
succeedCount = 0
diff --git a/dtmsvr/storage/redis/redis.go b/dtmsvr/storage/redis/redis.go
index b529c25..d24d658 100644
--- a/dtmsvr/storage/redis/redis.go
+++ b/dtmsvr/storage/redis/redis.go
@@ -270,11 +270,11 @@ return gid
}
}
-// ResetCronTime rest nextCronTime
-// Prevent multiple backoff from causing NextCronTime to be too long
-func (s *Store) ResetCronTime(timeout time.Duration, limit int64) (succeedCount int64, hasRemaining bool, err error) {
+// ResetCronTime reset nextCronTime
+// unfinished transactions need to be retried as soon as possible after business downtime is recovered
+func (s *Store) ResetCronTime(after time.Duration, limit int64) (succeedCount int64, hasRemaining bool, err error) {
next := time.Now().Unix()
- timeoutTimestamp := time.Now().Add(timeout).Unix()
+ timeoutTimestamp := time.Now().Add(after).Unix()
args := newArgList().AppendGid("").AppendRaw(timeoutTimestamp).AppendRaw(next).AppendRaw(limit)
lua := `-- ResetCronTime
local r = redis.call('ZRANGEBYSCORE', KEYS[3], ARGV[3], '+inf', 'LIMIT', 0, ARGV[5]+1)
diff --git a/dtmsvr/storage/registry/registry.go b/dtmsvr/storage/registry/registry.go
index 35df62a..f09692f 100644
--- a/dtmsvr/storage/registry/registry.go
+++ b/dtmsvr/storage/registry/registry.go
@@ -49,7 +49,7 @@ func GetStore() storage.Store {
// WaitStoreUp wait for db to go up
func WaitStoreUp() {
for err := GetStore().Ping(); err != nil; err = GetStore().Ping() {
- logger.Infof("wait store up")
+ logger.Infof("wait store up: %v", err)
time.Sleep(3 * time.Second)
}
}
diff --git a/dtmsvr/storage/sql/sql.go b/dtmsvr/storage/sql/sql.go
index c15c7fc..0ad3565 100644
--- a/dtmsvr/storage/sql/sql.go
+++ b/dtmsvr/storage/sql/sql.go
@@ -137,61 +137,44 @@ func (s *Store) TouchCronTime(global *storage.TransGlobalStore, nextCronInterval
// LockOneGlobalTrans finds GlobalTrans
func (s *Store) LockOneGlobalTrans(expireIn time.Duration) *storage.TransGlobalStore {
db := dbGet()
- getTime := func(second int) string {
- return map[string]string{
- "mysql": fmt.Sprintf("date_add(now(), interval %d second)", second),
- "postgres": fmt.Sprintf("current_timestamp + interval '%d second'", second),
- }[conf.Store.Driver]
- }
- expire := int(expireIn / time.Second)
- whereTime := fmt.Sprintf("next_cron_time < %s", getTime(expire))
owner := shortuuid.New()
- global := &storage.TransGlobalStore{}
- dbr := db.Must().Model(global).
- Where(whereTime + "and status in ('prepared', 'aborting', 'submitted')").
- Limit(1).
- Select([]string{"owner", "next_cron_time"}).
- Updates(&storage.TransGlobalStore{
- Owner: owner,
- NextCronTime: dtmutil.GetNextTime(conf.RetryInterval),
- })
- if dbr.RowsAffected == 0 {
+ nextCronTime := getTimeStr(int64(expireIn / time.Second))
+ where := map[string]string{
+ dtmimp.DBTypeMysql: fmt.Sprintf(`next_cron_time < '%s' and status in ('prepared', 'aborting', 'submitted') limit 1`, nextCronTime),
+ dtmimp.DBTypePostgres: fmt.Sprintf(`id in (select id from trans_global where next_cron_time < '%s' and status in ('prepared', 'aborting', 'submitted') limit 1 )`, nextCronTime),
+ }[conf.Store.Driver]
+
+ sql := fmt.Sprintf(`UPDATE trans_global SET update_time='%s',next_cron_time='%s', owner='%s' WHERE %s`,
+ getTimeStr(0),
+ getTimeStr(conf.RetryInterval),
+ owner,
+ where)
+ affected, err := dtmimp.DBExec(conf.Store.Driver, db.ToSQLDB(), sql)
+
+ dtmimp.PanicIf(err != nil, err)
+ if affected == 0 {
return nil
}
+ global := &storage.TransGlobalStore{}
db.Must().Where("owner=?", owner).First(global)
return global
}
-// ResetCronTime rest nextCronTime
-// Prevent multiple backoff from causing NextCronTime to be too long
-func (s *Store) ResetCronTime(timeout time.Duration, limit int64) (succeedCount int64, hasRemaining bool, err error) {
- db := dbGet()
- getTime := func(second int) string {
- return map[string]string{
- "mysql": fmt.Sprintf("date_add(now(), interval %d second)", second),
- "postgres": fmt.Sprintf("current_timestamp + interval '%d second'", second),
- }[conf.Store.Driver]
- }
- timeoutSecond := int(timeout / time.Second)
- whereTime := fmt.Sprintf("next_cron_time > %s", getTime(timeoutSecond))
- global := &storage.TransGlobalStore{}
- dbr := db.Must().Model(global).
- Where(whereTime + "and status in ('prepared', 'aborting', 'submitted')").
- Limit(int(limit)).
- Select([]string{"next_cron_time"}).
- Updates(&storage.TransGlobalStore{
- NextCronTime: dtmutil.GetNextTime(0),
- })
- succeedCount = dbr.RowsAffected
- if succeedCount == limit {
- var count int64
- db.Must().Model(global).Where(whereTime + "and status in ('prepared', 'aborting', 'submitted')").Limit(1).Count(&count)
- if count > 0 {
- hasRemaining = true
- }
- }
+// ResetCronTime reset nextCronTime
+// unfinished transactions need to be retried as soon as possible after business downtime is recovered
+func (s *Store) ResetCronTime(after time.Duration, limit int64) (succeedCount int64, hasRemaining bool, err error) {
+ nextCronTime := getTimeStr(int64(after / time.Second))
+ where := map[string]string{
+ dtmimp.DBTypeMysql: fmt.Sprintf(`next_cron_time > '%s' and status in ('prepared', 'aborting', 'submitted') limit %d`, nextCronTime, limit),
+ dtmimp.DBTypePostgres: fmt.Sprintf(`id in (select id from trans_global where next_cron_time > '%s' and status in ('prepared', 'aborting', 'submitted') limit %d )`, nextCronTime, limit),
+ }[conf.Store.Driver]
- return succeedCount, hasRemaining, dbr.Error
+ sql := fmt.Sprintf(`UPDATE trans_global SET update_time='%s',next_cron_time='%s' WHERE %s`,
+ getTimeStr(0),
+ getTimeStr(0),
+ where)
+ affected, err := dtmimp.DBExec(conf.Store.Driver, dbGet().ToSQLDB(), sql)
+ return affected, affected == limit, err
}
// SetDBConn sets db conn pool
@@ -213,3 +196,7 @@ func wrapError(err error) error {
dtmimp.E2P(err)
return err
}
+
+func getTimeStr(afterSecond int64) string {
+ return dtmutil.GetNextTime(afterSecond).Format("2006-01-02 15:04:05")
+}
diff --git a/dtmsvr/storage/store.go b/dtmsvr/storage/store.go
index 391c4dd..bd2b400 100644
--- a/dtmsvr/storage/store.go
+++ b/dtmsvr/storage/store.go
@@ -30,5 +30,5 @@ type Store interface {
ChangeGlobalStatus(global *TransGlobalStore, newStatus string, updates []string, finished bool)
TouchCronTime(global *TransGlobalStore, nextCronInterval int64, nextCronTime *time.Time)
LockOneGlobalTrans(expireIn time.Duration) *TransGlobalStore
- ResetCronTime(timeout time.Duration, limit int64) (succeedCount int64, hasRemaining bool, err error)
+ ResetCronTime(after time.Duration, limit int64) (succeedCount int64, hasRemaining bool, err error)
}
diff --git a/dtmsvr/storage/trans.go b/dtmsvr/storage/trans.go
index 4f37122..dd95290 100644
--- a/dtmsvr/storage/trans.go
+++ b/dtmsvr/storage/trans.go
@@ -11,7 +11,6 @@ import (
"github.com/dtm-labs/dtm/dtmcli"
"github.com/dtm-labs/dtm/dtmcli/dtmimp"
- "github.com/dtm-labs/dtm/dtmsvr/config"
"github.com/dtm-labs/dtm/dtmutil"
)
@@ -33,6 +32,7 @@ type TransGlobalStore struct {
Protocol string `json:"protocol,omitempty"`
FinishTime *time.Time `json:"finish_time,omitempty"`
RollbackTime *time.Time `json:"rollback_time,omitempty"`
+ RollbackReason string `json:"rollback_reason,omitempty"`
Options string `json:"options,omitempty"`
CustomData string `json:"custom_data,omitempty"`
NextCronInterval int64 `json:"next_cron_interval,omitempty"`
@@ -45,13 +45,18 @@ type TransGlobalStore struct {
// TableName TableName
func (g *TransGlobalStore) TableName() string {
- return config.Config.Store.TransGlobalTable
+ return "trans_global"
}
func (g *TransGlobalStore) String() string {
return dtmimp.MustMarshalString(g)
}
+// IsFinished return true if status == "failed" || status == "succeed"
+func (g *TransGlobalStore) IsFinished() bool {
+ return g.Status == dtmcli.StatusFailed || g.Status == dtmcli.StatusSucceed
+}
+
// TransBranchStore branch transaction
type TransBranchStore struct {
dtmutil.ModelBase
@@ -63,11 +68,12 @@ type TransBranchStore struct {
Status string `json:"status,omitempty"`
FinishTime *time.Time `json:"finish_time,omitempty"`
RollbackTime *time.Time `json:"rollback_time,omitempty"`
+ Error error `json:"-" gorm:"-"`
}
// TableName TableName
func (b *TransBranchStore) TableName() string {
- return config.Config.Store.TransBranchOpTable
+ return "trans_branch_op"
}
func (b *TransBranchStore) String() string {
diff --git a/dtmsvr/trans_status.go b/dtmsvr/trans_status.go
index 6f6a344..fa1e51e 100644
--- a/dtmsvr/trans_status.go
+++ b/dtmsvr/trans_status.go
@@ -36,7 +36,22 @@ func (t *TransGlobal) touchCronTime(ctype cronType, delay uint64) {
logger.Infof("TouchCronTime for: %s", t.TransGlobalStore.String())
}
-func (t *TransGlobal) changeStatus(status string) {
+type changeStatusParams struct {
+ rollbackReason string
+}
+type changeStatusOption func(c *changeStatusParams)
+
+func withRollbackReason(rollbackReason string) changeStatusOption {
+ return func(c *changeStatusParams) {
+ c.rollbackReason = rollbackReason
+ }
+}
+
+func (t *TransGlobal) changeStatus(status string, opts ...changeStatusOption) {
+ statusParams := &changeStatusParams{}
+ for _, opt := range opts {
+ opt(statusParams)
+ }
updates := []string{"status", "update_time"}
now := time.Now()
if status == dtmcli.StatusSucceed {
@@ -46,6 +61,10 @@ func (t *TransGlobal) changeStatus(status string) {
t.RollbackTime = &now
updates = append(updates, "rollback_time")
}
+ if statusParams.rollbackReason != "" {
+ t.RollbackReason = statusParams.rollbackReason
+ updates = append(updates, "rollback_reason")
+ }
t.UpdateTime = &now
GetStore().ChangeGlobalStatus(&t.TransGlobalStore, status, updates, status == dtmcli.StatusSucceed || status == dtmcli.StatusFailed)
logger.Infof("ChangeGlobalStatus to %s ok for %s", status, t.TransGlobalStore.String())
@@ -171,6 +190,7 @@ func (t *TransGlobal) getBranchResult(branch *TransBranch) (string, error) {
if err == nil {
return dtmcli.StatusSucceed, nil
} else if t.TransType == "saga" && branch.Op == dtmimp.OpAction && errors.Is(err, dtmcli.ErrFailure) {
+ branch.Error = fmt.Errorf("url:%s return failed: %w", branch.URL, err)
return dtmcli.StatusFailed, nil
} else if errors.Is(err, dtmcli.ErrOngoing) {
return "", dtmcli.ErrOngoing
diff --git a/dtmsvr/trans_type_saga.go b/dtmsvr/trans_type_saga.go
index 763d714..9117515 100644
--- a/dtmsvr/trans_type_saga.go
+++ b/dtmsvr/trans_type_saga.go
@@ -49,13 +49,14 @@ type branchResult struct {
status string
started bool
op string
+ err error
}
func (t *transSagaProcessor) ProcessOnce(branches []TransBranch) error {
// when saga tasks is fetched, it always need to process
logger.Debugf("status: %s timeout: %t", t.Status, t.isTimeout())
if t.Status == dtmcli.StatusSubmitted && t.isTimeout() {
- t.changeStatus(dtmcli.StatusAborting)
+ t.changeStatus(dtmcli.StatusAborting, withRollbackReason(fmt.Sprintf("Timeout after %d seconds", t.TimeoutToFail)))
}
n := len(branches)
@@ -73,6 +74,7 @@ func (t *transSagaProcessor) ProcessOnce(branches []TransBranch) error {
}
// resultStats
var rsAToStart, rsAStarted, rsADone, rsAFailed, rsASucceed, rsCToStart, rsCDone, rsCSucceed int
+ var failureError error
branchResults := make([]branchResult, n) // save the branch result
for i := 0; i < n; i++ {
b := branches[i]
@@ -125,9 +127,9 @@ func (t *transSagaProcessor) ProcessOnce(branches []TransBranch) error {
if x := recover(); x != nil {
err = dtmimp.AsError(x)
}
- resultChan <- branchResult{index: i, status: branches[i].Status, op: branches[i].Op}
+ resultChan <- branchResult{index: i, status: branches[i].Status, op: branches[i].Op, err: branches[i].Error}
if err != nil && !errors.Is(err, dtmcli.ErrOngoing) {
- logger.Errorf("exec branch error: %v", err)
+ logger.Errorf("exec branch %s %s %s error: %v", branches[i].BranchID, branches[i].Op, branches[i].URL, err)
}
}()
err = t.execBranch(&branches[i], i)
@@ -172,6 +174,7 @@ func (t *transSagaProcessor) ProcessOnce(branches []TransBranch) error {
rsADone++
if r.status == dtmcli.StatusFailed {
rsAFailed++
+ failureError = r.err
} else if r.status == dtmcli.StatusSucceed {
rsASucceed++
}
@@ -219,8 +222,11 @@ func (t *transSagaProcessor) ProcessOnce(branches []TransBranch) error {
t.changeStatus(dtmcli.StatusSucceed)
return nil
}
- if t.Status == dtmcli.StatusSubmitted && (rsAFailed > 0 || t.isTimeout()) {
- t.changeStatus(dtmcli.StatusAborting)
+ if t.Status == dtmcli.StatusSubmitted && rsAFailed > 0 {
+ t.changeStatus(dtmcli.StatusAborting, withRollbackReason(failureError.Error()))
+ }
+ if t.Status == dtmcli.StatusSubmitted && t.isTimeout() {
+ t.changeStatus(dtmcli.StatusAborting, withRollbackReason(fmt.Sprintf("Timeout after %d seconds", t.TimeoutToFail)))
}
if t.Status == dtmcli.StatusAborting {
prepareToCompensate()
diff --git a/dtmsvr/trans_type_tcc.go b/dtmsvr/trans_type_tcc.go
index 5146226..11f23b7 100644
--- a/dtmsvr/trans_type_tcc.go
+++ b/dtmsvr/trans_type_tcc.go
@@ -1,6 +1,8 @@
package dtmsvr
import (
+ "fmt"
+
"github.com/dtm-labs/dtm/dtmcli"
"github.com/dtm-labs/dtm/dtmcli/dtmimp"
"github.com/dtm-labs/dtm/dtmcli/logger"
@@ -23,7 +25,7 @@ func (t *transTccProcessor) ProcessOnce(branches []TransBranch) error {
return nil
}
if t.Status == dtmcli.StatusPrepared && t.isTimeout() {
- t.changeStatus(dtmcli.StatusAborting)
+ t.changeStatus(dtmcli.StatusAborting, withRollbackReason(fmt.Sprintf("Timeout after %d seconds", t.TimeoutToFail)))
}
op := dtmimp.If(t.Status == dtmcli.StatusSubmitted, dtmimp.OpConfirm, dtmimp.OpCancel).(string)
for current := len(branches) - 1; current >= 0; current-- {
diff --git a/dtmsvr/trans_type_xa.go b/dtmsvr/trans_type_xa.go
index d4ca3b3..c74f188 100644
--- a/dtmsvr/trans_type_xa.go
+++ b/dtmsvr/trans_type_xa.go
@@ -1,6 +1,8 @@
package dtmsvr
import (
+ "fmt"
+
"github.com/dtm-labs/dtm/dtmcli"
"github.com/dtm-labs/dtm/dtmcli/dtmimp"
)
@@ -22,7 +24,7 @@ func (t *transXaProcessor) ProcessOnce(branches []TransBranch) error {
return nil
}
if t.Status == dtmcli.StatusPrepared && t.isTimeout() {
- t.changeStatus(dtmcli.StatusAborting)
+ t.changeStatus(dtmcli.StatusAborting, withRollbackReason(fmt.Sprintf("Timeout after %d seconds", t.TimeoutToFail)))
}
currentType := dtmimp.If(t.Status == dtmcli.StatusSubmitted, dtmimp.OpCommit, dtmimp.OpRollback).(string)
for i, branch := range branches {
diff --git a/dtmutil/db.go b/dtmutil/db.go
index 1862870..043f7f9 100644
--- a/dtmutil/db.go
+++ b/dtmutil/db.go
@@ -100,7 +100,7 @@ func DbGet(conf dtmcli.DBConf, ops ...func(*gorm.DB)) *DB {
dsn := dtmimp.GetDsn(conf)
db, ok := dbs.Load(dsn)
if !ok {
- logger.Infof("connecting '%s' '%s' '%s' '%d'", conf.Driver, conf.Host, conf.User, conf.Port)
+ logger.Infof("connecting '%s' '%s' '%s' '%d' '%s'", conf.Driver, conf.Host, conf.User, conf.Port, conf.Db)
db1, err := gorm.Open(getGormDialetor(conf.Driver, dsn), &gorm.Config{
SkipDefaultTransaction: true,
})
diff --git a/dtmutil/utils.go b/dtmutil/utils.go
index 06b39a7..e7bbeba 100644
--- a/dtmutil/utils.go
+++ b/dtmutil/utils.go
@@ -64,7 +64,7 @@ func WrapHandler(fn func(*gin.Context) interface{}) gin.HandlerFunc {
}
}
-// WrapHandler2 wrap a function te bo the handler of gin request
+// WrapHandler2 wrap a function to be the handler of gin request
// used by dtmsvr
func WrapHandler2(fn func(*gin.Context) interface{}) gin.HandlerFunc {
return func(c *gin.Context) {
@@ -168,7 +168,7 @@ func RunSQLScript(conf dtmcli.DBConf, script string, skipDrop bool) {
if s == "" || (skipDrop && strings.Contains(s, "drop")) {
continue
}
- _, err = dtmimp.DBExec(con, s)
+ _, err = dtmimp.DBExec(conf.Driver, con, s)
logger.FatalIfError(err)
logger.Infof("sql scripts finished: %s", s)
}
diff --git a/go.mod b/go.mod
index 26ebd15..a45dc32 100644
--- a/go.mod
+++ b/go.mod
@@ -6,12 +6,13 @@ require (
bou.ke/monkey v1.0.2
github.com/BurntSushi/toml v0.4.1 // indirect
github.com/dtm-labs/dtmdriver v0.0.3
- github.com/dtm-labs/dtmdriver-gozero v0.0.4
+ github.com/dtm-labs/dtmdriver-gozero v0.0.5
github.com/dtm-labs/dtmdriver-http v1.2.2
github.com/dtm-labs/dtmdriver-kratos v0.0.8
github.com/dtm-labs/dtmdriver-polaris v0.0.4
github.com/dtm-labs/dtmdriver-protocol1 v0.0.1
github.com/gin-gonic/gin v1.7.7
+ github.com/go-playground/validator/v10 v10.11.0 // indirect
github.com/go-redis/redis/v8 v8.11.4
github.com/go-resty/resty/v2 v2.7.0
github.com/go-sql-driver/mysql v1.6.0
@@ -22,14 +23,16 @@ require (
github.com/onsi/gomega v1.16.0
github.com/prometheus/client_golang v1.11.0
github.com/stretchr/testify v1.7.1
+ github.com/ugorji/go v1.2.7 // indirect
go.etcd.io/bbolt v1.3.6
- go.mongodb.org/mongo-driver v1.8.3
+ go.mongodb.org/mongo-driver v1.9.0
go.uber.org/automaxprocs v1.5.1
go.uber.org/zap v1.21.0
- golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa // indirect
- google.golang.org/grpc v1.45.0
+ golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e // indirect
+ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a // indirect
+ google.golang.org/grpc v1.46.2
google.golang.org/protobuf v1.28.0
- gopkg.in/yaml.v2 v2.4.0
+ gopkg.in/yaml.v3 v3.0.1
gorm.io/driver/mysql v1.0.3
gorm.io/driver/postgres v1.2.1
gorm.io/gorm v1.22.2
diff --git a/go.sum b/go.sum
index 0535ea6..98d85de 100644
--- a/go.sum
+++ b/go.sum
@@ -67,8 +67,10 @@ github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRF
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc=
github.com/alicebob/miniredis/v2 v2.17.0/go.mod h1:gquAfGbzn92jvtrSC69+6zZnwSODVXVpYDRaGhWaL6I=
-github.com/aliyun/alibaba-cloud-sdk-go v1.61.18 h1:zOVTBdCKFd9JbCKz9/nt+FovbjPFmb7mUnp8nH9fQBA=
github.com/aliyun/alibaba-cloud-sdk-go v1.61.18/go.mod h1:v8ESoHo4SyHmuB4b1tJqDHxfTGEciD+yhvOU/5s1Rfk=
+github.com/aliyun/alibaba-cloud-sdk-go v1.61.1402/go.mod h1:RcDobYh8k5VP6TNybz9m++gL3ijVI5wueVr0EM10VsU=
+github.com/aliyun/alibaba-cloud-sdk-go v1.61.1620 h1:diBUSNskvZjiX1LFa3I+AfHaVnKvphXHddf0eVuCVFg=
+github.com/aliyun/alibaba-cloud-sdk-go v1.61.1620/go.mod h1:RcDobYh8k5VP6TNybz9m++gL3ijVI5wueVr0EM10VsU=
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
@@ -85,6 +87,7 @@ github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
github.com/bkaradzic/go-lz4 v1.0.0/go.mod h1:0YdlkowM3VswSROI7qDxhRvJ3sLhlFrRRwjwegp5jy4=
+github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s=
github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs=
github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
@@ -106,6 +109,7 @@ github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XP
github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
+github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I=
github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
@@ -131,10 +135,8 @@ github.com/dtm-labs/dtmdriver v0.0.1/go.mod h1:fLiEeD2BPwM9Yq96TfcP9KpbTwFsn5nTx
github.com/dtm-labs/dtmdriver v0.0.2/go.mod h1:fLiEeD2BPwM9Yq96TfcP9KpbTwFsn5nTxa/PP0jmFuk=
github.com/dtm-labs/dtmdriver v0.0.3 h1:9iAtvXKR3lJXQ7dvS87e4xdtmqkzN+ofek+CF9AvUSY=
github.com/dtm-labs/dtmdriver v0.0.3/go.mod h1:fLiEeD2BPwM9Yq96TfcP9KpbTwFsn5nTxa/PP0jmFuk=
-github.com/dtm-labs/dtmdriver-gozero v0.0.3 h1:KXaEFYzykSEhiLB2+baV8X1PaHLKh85bpJISK8+H86E=
-github.com/dtm-labs/dtmdriver-gozero v0.0.3/go.mod h1:B5FqzfvzGe2AcB8MpAP34eSLszkCd6hm+t5KJN2Fu/o=
-github.com/dtm-labs/dtmdriver-gozero v0.0.4 h1:GN+x3pmk545BgvbR4oiKhJ7N8k5yZ2rkG1aCwj8ZDZ8=
-github.com/dtm-labs/dtmdriver-gozero v0.0.4/go.mod h1:B5FqzfvzGe2AcB8MpAP34eSLszkCd6hm+t5KJN2Fu/o=
+github.com/dtm-labs/dtmdriver-gozero v0.0.5 h1:cMBkURDRPcb1Y6/kY+x/yxYA8KWMG+fkK6b+cs4WXKo=
+github.com/dtm-labs/dtmdriver-gozero v0.0.5/go.mod h1:U4nIisQ5SBZrajp7ky1Bi0eBxPiGqVy+tOs47beobY4=
github.com/dtm-labs/dtmdriver-http v1.2.2 h1:QOul+PpK1KQyXXx5viNrHrEFIc/nFxmX4fJfI3DLUqI=
github.com/dtm-labs/dtmdriver-http v1.2.2/go.mod h1:UtWShS61TiiudZUAabQ2ww0CzSEpBYF3AS3F3G2Jc2o=
github.com/dtm-labs/dtmdriver-kratos v0.0.8 h1:AAIfFzpzuu7K3B/wpx71y0FdZqO1X/Bsklva0bayS9s=
@@ -156,8 +158,10 @@ github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.m
github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ=
github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0=
+github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
+github.com/fastly/go-utils v0.0.0-20180712184237-d95a45783239/go.mod h1:Gdwt2ce0yfBxPvZrHkprdPPTTS3N5rwmLE8T22KBXlw=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM=
@@ -178,8 +182,10 @@ github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm
github.com/gin-gonic/gin v1.7.7 h1:3DoBmSbJbZAWqXJC3SLjAPfutPJJRN1U5pALB7EeTTs=
github.com/gin-gonic/gin v1.7.7/go.mod h1:axIBovoeJpVj8S3BwE0uPMTeReE4+AfFtqpqaZ1qq1U=
github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q=
-github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w=
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
+github.com/go-errors/errors v1.4.1/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og=
+github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA=
+github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og=
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
@@ -218,12 +224,15 @@ github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh
github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A=
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
github.com/go-playground/form/v4 v4.2.0/go.mod h1:q1a2BY+AQUUzhl6xA/6hBetay6dEIhMHjgvJiGo6K7U=
-github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q=
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
-github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no=
+github.com/go-playground/locales v0.14.0 h1:u50s323jtVGugKlcYeyzC0etD1HifMjqmJqb8WugfUU=
+github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs=
github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
-github.com/go-playground/validator/v10 v10.4.1 h1:pH2c5ADXtd66mxoE0Zm9SUhxE20r7aM3F26W0hOn+GE=
+github.com/go-playground/universal-translator v0.18.0 h1:82dyy6p4OuJq4/CByFNOn/jYrnRPArHwAcmLoJZxyho=
+github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA=
github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4=
+github.com/go-playground/validator/v10 v10.11.0 h1:0W+xRM511GY47Yy3bZUbJVitCNg2BOGlCyvTqsp/xIw=
+github.com/go-playground/validator/v10 v10.11.0/go.mod h1:i+3WkQ1FvaUjjxh1kSvIA4dMGDBiPU55YFDl0WbKdWU=
github.com/go-redis/redis v6.15.9+incompatible h1:K0pv1D7EQUjfyoMql+r/jZqCLizCGKFlFgcHWWmHQjg=
github.com/go-redis/redis v6.15.9+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=
github.com/go-redis/redis/v8 v8.11.4 h1:kHoYkfZP6+pe04aFTnhDH6GDROa5yJdHJVNxV3F46Tg=
@@ -444,14 +453,19 @@ github.com/jcmturner/gofork v1.0.0/go.mod h1:MK8+TM0La+2rjBD4jE12Kj1pCCxK7d2LK/U
github.com/jcmturner/goidentity/v6 v6.0.1/go.mod h1:X1YW3bgtvwAXju7V3LCIMpY0Gbxyjn/mY9zx4tFonSg=
github.com/jcmturner/gokrb5/v8 v8.4.2/go.mod h1:sb+Xq/fTY5yktf/VxLsE3wlfPqQjp0aWNYyvBVK62bc=
github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc=
+github.com/jehiah/go-strftime v0.0.0-20171201141054-1d33003b3869/go.mod h1:cJ6Cj7dQo+O6GJNiMx+Pa94qKj+TG8ONdKHgMNIyyag=
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
github.com/jinzhu/now v1.1.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
github.com/jinzhu/now v1.1.2 h1:eVKgfIdy9b6zbWBMgFpfDPoAMifwSZagU9HmEU6zgiI=
github.com/jinzhu/now v1.1.2/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
-github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM=
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
+github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
+github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
+github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8=
+github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks=
+github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA=
github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
@@ -487,8 +501,12 @@ github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
-github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y=
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
+github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w=
+github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY=
+github.com/lestrrat/go-envload v0.0.0-20180220120943-6ed08b54a570/go.mod h1:BLt8L9ld7wVsvEWQbuLrUZnCMnUmLZ+CGDzKtclrTlE=
+github.com/lestrrat/go-file-rotatelogs v0.0.0-20180223000712-d3151e2a480f/go.mod h1:UGmTpUd3rjbtfIpwAPrcfmGf/Z1HS95TATB+m57TPB8=
+github.com/lestrrat/go-strftime v0.0.0-20180220042222-ba3bf9c1d042/go.mod h1:TPpsiPUEh0zFL1Snz4crhMlBe60PYxRHr5oFF3rRYg0=
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
@@ -551,6 +569,7 @@ github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8m
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
+github.com/nacos-group/nacos-sdk-go v1.0.9/go.mod h1:hlAPn3UdzlxIlSILAyOXKxjFSvDJ9oLzTJ9hLAK1KzA=
github.com/nacos-group/nacos-sdk-go v1.1.1 h1:beczWcOoTaVBMgCgikqvZflrN5Xbw7pWAWpxl+VJGIA=
github.com/nacos-group/nacos-sdk-go v1.1.1/go.mod h1:UHOtQNQY/qpk2dhg6gDq8u5+/CEIc3+lWmrmxEzX0/g=
github.com/natefinch/lumberjack v2.0.0+incompatible h1:4QJd3OLAMgj7ph+yZTuX13Ld4UpgHp07nNdFX7mqFfM=
@@ -626,6 +645,7 @@ github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJ
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
+github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg=
github.com/rogpeppe/go-internal v1.8.1/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o=
github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
@@ -673,15 +693,19 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/tebeka/strftime v0.1.3/go.mod h1:7wJm3dZlpr4l/oVK0t1HYIc4rMzQ2XJlOMIUJUJH6XQ=
github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4=
github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
github.com/tklauser/go-sysconf v0.3.9/go.mod h1:11DU/5sG7UexIrp/O6g35hrWzu0JxlwQ3LSFUzyeuhs=
github.com/tklauser/numcpus v0.3.0/go.mod h1:yFGUr7TUHQRAhyqBcEg0Ge34zDBAsIvJJcyE6boqnA8=
+github.com/toolkits/concurrent v0.0.0-20150624120057-a4371d70e3e3/go.mod h1:QDlpd3qS71vYtakd2hmdpqhJ9nwv6mD6A30bQ1BPBFE=
github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM=
-github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo=
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
-github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs=
+github.com/ugorji/go v1.2.7 h1:qYhyWUUd6WbiM+C6JZAUkIJt/1WrjzNHY9+KCIjVqTo=
+github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M=
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
+github.com/ugorji/go/codec v1.2.7 h1:YPXUKf7fYbp/y8xloBqZOw2qaVggbfwMlI8WM3wZUJ0=
+github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY=
github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI=
github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c=
github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
@@ -700,10 +724,13 @@ github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1
github.com/yuin/gopher-lua v0.0.0-20200816102855-ee81675732da/go.mod h1:E1AXubJBdNmFERAOucpDIxNzeGfLzg0mYh+UfMWdChA=
github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q=
github.com/zeromicro/go-zero v1.3.0/go.mod h1:Hy4o1VFAt32lXaQMbaBhoFeZjA/rJqJ4PTGNdGsURcc=
-github.com/zeromicro/go-zero v1.3.2 h1:2HcmceZDEGwZWvofCG+0GXyh+Gtz/wKCW4Fq8Mb7KIg=
github.com/zeromicro/go-zero v1.3.2/go.mod h1:DEj3Fwj1Ui1ltsgf6YqwTL9nD4+tYzIRX0c1pWtQo1E=
+github.com/zeromicro/go-zero v1.3.3 h1:6qv9PcfqfB1tMgp1FJlP1LfWSZ4XD+FwojvA2h5LL2k=
+github.com/zeromicro/go-zero v1.3.3/go.mod h1:LwuYc2V04ZHhWPWGJYQ+kJ5DT4QSkeaZGqXiQcpkfks=
github.com/zeromicro/zero-contrib/zrpc/registry/consul v0.0.0-20220228111653-d672d81f39ab h1:cgWxVhYV2Mr4ZClJTecxt0V5u5jvrayLzFYlUzoG5qI=
github.com/zeromicro/zero-contrib/zrpc/registry/consul v0.0.0-20220228111653-d672d81f39ab/go.mod h1:kM7gqMjv0B7QI1UsmJhN5UVWxQao9Oe3Jt3JnXc9o+c=
+github.com/zeromicro/zero-contrib/zrpc/registry/nacos v0.0.0-20220525162615-f10f16d580d6 h1:2+DgXySLxSsB0LoYgk+AinZKnWq2mc5lxbqUQ7qTcvY=
+github.com/zeromicro/zero-contrib/zrpc/registry/nacos v0.0.0-20220525162615-f10f16d580d6/go.mod h1:5yKg0EdtswP7sn1snNAkZ/6aj/zBYcyWOqTpLSAtW3M=
go.etcd.io/bbolt v1.3.6 h1:/ecaJf0sk1l4l6V4awd65v2C3ILy7MSj+s/x1ADCIMU=
go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4=
go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs=
@@ -718,23 +745,23 @@ go.etcd.io/etcd/client/v3 v3.5.0/go.mod h1:AIKXXVX/DQXtfTEqBryiLTUXwON+GuvO6Z7lL
go.etcd.io/etcd/client/v3 v3.5.1/go.mod h1:OnjH4M8OnAotwaB2l9bVgZzRFKru7/ZMoS46OtKyd3Q=
go.etcd.io/etcd/client/v3 v3.5.2 h1:WdnejrUtQC4nCxK0/dLTMqKOB+U5TP/2Ya0BJL+1otA=
go.etcd.io/etcd/client/v3 v3.5.2/go.mod h1:kOOaWFFgHygyT0WlSmL8TJiXmMysO/nNUlEsSsN6W4o=
-go.mongodb.org/mongo-driver v1.8.3 h1:TDKlTkGDKm9kkJVUOAXDK5/fkqKHJVwYQSpoRfB43R4=
-go.mongodb.org/mongo-driver v1.8.3/go.mod h1:0sQWfOeY63QTntERDJJ/0SuKK0T1uVSgKCuAROlKEPY=
+go.mongodb.org/mongo-driver v1.9.0 h1:f3aLGJvQmBl8d9S40IL+jEyBC6hfLPbJjv9t5hEM9ck=
+go.mongodb.org/mongo-driver v1.9.0/go.mod h1:0sQWfOeY63QTntERDJJ/0SuKK0T1uVSgKCuAROlKEPY=
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opentelemetry.io/otel v1.3.0/go.mod h1:PWIKzi6JCp7sM0k9yZ43VX+T345uNbAkDKwHVjb2PTs=
-go.opentelemetry.io/otel v1.6.3 h1:FLOfo8f9JzFVFVyU+MSRJc2HdEAXQgm7pIv2uFKRSZE=
-go.opentelemetry.io/otel v1.6.3/go.mod h1:7BgNga5fNlF/iZjG06hM3yofffp0ofKCDwSXx1GC4dI=
+go.opentelemetry.io/otel v1.7.0 h1:Z2lA3Tdch0iDcrhJXDIlC94XE+bxok1F9B+4Lz/lGsM=
+go.opentelemetry.io/otel v1.7.0/go.mod h1:5BdUoMIz5WEs0vt0CUEMtSSaTSHBBVwrhnz7+nrD5xk=
go.opentelemetry.io/otel/exporters/jaeger v1.3.0/go.mod h1:KoYHi1BtkUPncGSRtCe/eh1ijsnePhSkxwzz07vU0Fc=
go.opentelemetry.io/otel/exporters/zipkin v1.3.0/go.mod h1:LxGGfHIYbvsFnrJtBcazb0yG24xHdDGrT/H6RB9r3+8=
go.opentelemetry.io/otel/sdk v1.3.0 h1:3278edCoH89MEJ0Ky8WQXVmDQv3FX4ZJ3Pp+9fJreAI=
go.opentelemetry.io/otel/sdk v1.3.0/go.mod h1:rIo4suHNhQwBIPg9axF8V9CA72Wz2mKF1teNrup8yzs=
go.opentelemetry.io/otel/trace v1.3.0/go.mod h1:c/VDhno8888bvQYmbYLqe41/Ldmr/KKunbvWM4/fEjk=
-go.opentelemetry.io/otel/trace v1.6.3 h1:IqN4L+5b0mPNjdXIiZ90Ni4Bl5BRkDQywePLWemd9bc=
-go.opentelemetry.io/otel/trace v1.6.3/go.mod h1:GNJQusJlUgZl9/TQBPKU/Y/ty+0iVB5fjhKeJGZPGFs=
+go.opentelemetry.io/otel/trace v1.7.0 h1:O37Iogk1lEkMRXewVtZ1BBTVn5JEp8GrJvP92bJqC6o=
+go.opentelemetry.io/otel/trace v1.7.0/go.mod h1:fzLSB9nqR2eXzxPXb2JW9IKE+ScyXA48yyE4TNvoHqU=
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
@@ -784,8 +811,9 @@ golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5y
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20210920023735-84f357641f63/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
-golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa h1:idItI2DDfCokpg0N51B2VtiLdJ4vAuXC9fnCb2gACo4=
-golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
+golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
+golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e h1:T8NU3HyQ8ClP4SEE+KbFlg6n0NhuTsN4MyznaarGsZM=
+golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@@ -865,9 +893,11 @@ golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qx
golang.org/x/net v0.0.0-20210917221730-978cfadd31cf/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211029224645-99673261e6eb/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220114011407-0dd24b26b47d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
-golang.org/x/net v0.0.0-20220225172249-27dd8689420f h1:oA4XRj0qtSt8Yo1Zms0CUlsT3KG69V2UGQWPBxujDmc=
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
+golang.org/x/net v0.0.0-20220421235706-1d1ef9303861 h1:yssD99+7tqHWO5Gwh81phT+67hg+KttniBr6UnEXOY8=
+golang.org/x/net v0.0.0-20220421235706-1d1ef9303861/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -886,8 +916,9 @@ golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20220513210516-0976fa681c29 h1:w8s32wxx3sY+OjLlv9qltkLU5yvJzxjjgiHWLjdIcw4=
+golang.org/x/sync v0.0.0-20220513210516-0976fa681c29/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -942,6 +973,7 @@ golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20201112073958-5cba982894dd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -952,14 +984,16 @@ golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210816074244-15123e1e1f71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220111092808-5a964db01320/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20220412211240-33da011f77ad h1:ntjMns5wyP/fN65tdBD4g8J5w8n015+iIIs9rtjXkY0=
-golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220422013727-9388b58f7150/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a h1:dGzPydgVsqGcTRVwiLJ1jVbufYwmzD3LfVPLKsKg+0k=
+golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
@@ -1103,8 +1137,9 @@ google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6D
google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
google.golang.org/genproto v0.0.0-20220112215332-a9c7c0acf9f2/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/genproto v0.0.0-20220126215142-9970aeb2e350/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
-google.golang.org/genproto v0.0.0-20220228195345-15d65a4533f7 h1:ntPPoHzFW6Xp09ueznmahONZufyoSakK/piXnr2BU3I=
google.golang.org/genproto v0.0.0-20220228195345-15d65a4533f7/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI=
+google.golang.org/genproto v0.0.0-20220422154200-b37d22cd5731 h1:nquqdM9+ps0JZcIiI70+tqoaIFS5Ql4ZuK8UXnz3HfE=
+google.golang.org/genproto v0.0.0-20220422154200-b37d22cd5731/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
@@ -1124,8 +1159,10 @@ google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9K
google.golang.org/grpc v1.41.0/go.mod h1:U3l9uK9J0sini8mHphKoXyaqDA/8VyGnDee1zzIUK6k=
google.golang.org/grpc v1.43.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
-google.golang.org/grpc v1.45.0 h1:NEpgUqV3Z+ZjkqMsxMg11IaDrXY4RY6CQukSGK0uI1M=
google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ=
+google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
+google.golang.org/grpc v1.46.2 h1:u+MLGgVf7vRdjEYZ8wDFhAVNmhkbJ5hmrA1LMWK1CAQ=
+google.golang.org/grpc v1.46.2/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
@@ -1154,8 +1191,10 @@ gopkg.in/h2non/gock.v1 v1.1.2/go.mod h1:n7UGz/ckNChHiK05rDoiC4MYSunEC/lyaUm2WWaD
gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s=
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
-gopkg.in/ini.v1 v1.42.0 h1:7N3gPTt50s8GuLortA00n8AqRTk75qOP98+mTPpgzRk=
gopkg.in/ini.v1 v1.42.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
+gopkg.in/ini.v1 v1.66.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
+gopkg.in/ini.v1 v1.66.6 h1:LATuAqN/shcYAOkv3wl2L4rkaKqkcgTBQjOyYDvcPKI=
+gopkg.in/ini.v1 v1.66.6/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8=
gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
@@ -1170,8 +1209,9 @@ gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
-gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
+gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gorm.io/driver/mysql v1.0.3 h1:+JKBYPfn1tygR1/of/Fh2T8iwuVwzt+PEJmKaXzMQXg=
gorm.io/driver/mysql v1.0.3/go.mod h1:twGxftLBlFgNVNakL7F+P/x9oYqoymG3YYT8cAfI9oI=
gorm.io/driver/postgres v1.2.1 h1:JDQKnF7MC51dgL09Vbydc5kl83KkVDlcXfSPJ+xhh68=
diff --git a/helper/.goreleaser.yml b/helper/.goreleaser.yml
index 83e0158..02e6060 100644
--- a/helper/.goreleaser.yml
+++ b/helper/.goreleaser.yml
@@ -12,9 +12,9 @@ builds:
dir: .
main: main.go
ldflags:
- - -s -w -X main.Version={{.Version}}
+ - -s -w -X main.Version=v{{.Version}}
- id: dtm_arm64
- env: [ CGO_ENABLED=0 ]
+ env: [CGO_ENABLED=0]
goos:
- darwin
goarch:
@@ -22,4 +22,4 @@ builds:
dir: .
main: main.go
ldflags:
- - -s -w -X main.Version={{.Version}}
+ - -s -w -X main.Version=v{{.Version}}
diff --git a/helper/Dockerfile-release b/helper/Dockerfile-release
index 45127c2..568de9a 100644
--- a/helper/Dockerfile-release
+++ b/helper/Dockerfile-release
@@ -1,5 +1,11 @@
# syntax=docker/dockerfile:1
-FROM --platform=$TARGETPLATFORM golang:1.16-alpine as builder
+# FROM node:14.19-alpine as builder1
+# ARG RELEASE_VERSION
+# WORKDIR /app/dtm
+# COPY . .
+# RUN cd admin && yarn && VITE_ADMIN_VERSION=$RELEASE_VERSION yarn build
+
+FROM --platform=$TARGETPLATFORM golang:1.16-alpine as builder2
ARG TARGETARCH
ARG TARGETOS
ARG RELEASE_VERSION
@@ -7,9 +13,10 @@ WORKDIR /app/dtm
# RUN go env -w GOPROXY=https://mirrors.aliyun.com/goproxy/,direct
EXPOSE 8080
COPY . .
+# COPY --from=builder1 /app/dtm/admin/dist /app/dtm/admin
RUN CGO_ENABLED=0 GOOS=$TARGETOS GOARCH=$TARGETARCH go build -ldflags="-s -w -X main.Version=$RELEASE_VERSION"
FROM --platform=$TARGETPLATFORM alpine
-COPY --from=builder /app/dtm/dtm /app/dtm/
+COPY --from=builder2 /app/dtm/dtm /app/dtm/
WORKDIR /app/dtm
ENTRYPOINT ["/app/dtm/dtm"]
diff --git a/helper/README-cn.md b/helper/README-cn.md
index f7a9bfe..2153ae3 100644
--- a/helper/README-cn.md
+++ b/helper/README-cn.md
@@ -9,14 +9,7 @@
# 跨语言分布式事务管理器
-DTM是一款变革性的分布式事务框架,提供了傻瓜式的使用方式,极大的降低了分布式事务的使用门槛,改变了“能不用分布式事务就不用”的行业现状。 dtm 的应用范围非常广,可以应用于以下常见的领域:
-- [秒杀系统,保证Redis中精准的库存,和最终创建的订单完全一致,无需手动调整](https://dtm.pub/app/flash.html)
-- [保证缓存与DB的一致性](https://dtm.pub/app/cache.html)
-- [非单体的订单系统,大幅简化架构](https://dtm.pub/app/order.html)
-- 微服务架构(已原生支持[go-zero](https://github.com/zeromicro/go-zero)等框架)中跨服务更新数据保证一致性
-
-他优雅的解决了幂等、空补偿、悬挂等分布式事务难题,提供跨语言,跨存储引擎组合事务的强大功能:
-
+DTM是一款变革性的分布式事务框架,提供了傻瓜式的使用方式,极大的降低了分布式事务的使用门槛,改变了“能不用分布式事务就不用”的行业现状,优雅的解决了服务间的数据一致性问题。
## 谁在使用DTM(仅列出部分)
[Tencent 腾讯](https://dtm.pub/other/using.html#tencent)
@@ -25,39 +18,26 @@ DTM是一款变革性的分布式事务框架,提供了傻瓜式的使用方
[Ivydad 常青藤爸爸](https://dtm.pub/other/using.html#ivydad)
-## 亮点
-
-* 极易上手
- - 零配置启动服务,提供非常简单的HTTP接口,极大降低上手分布式事务的难度,新手也能快速接入
-* 跨语言
- - 可适合多语言栈的公司使用。方便go、python、php、nodejs、ruby、c# 各类语言使用。
-* 使用简单
- - 开发者不再担心悬挂、空补偿、幂等各类问题,首创子事务屏障技术代为处理
-* 易部署、易扩展
- - 依赖mysql/redis,部署简单,易集群化,易水平扩展
-* 多种分布式事务协议支持
- - TCC、SAGA、XA、二阶段消息,一站式解决所有分布式事务问题
-
-## 与其他框架对比
-
-非Java语言类的,暂未看到除dtm之外的成熟框架,因此这里将DTM和Java中最成熟的Seata对比:
+[更多](https://dtm.pub/other/using.html)
-| 特性| DTM | SEATA |备注|
-|:-----:|:----:|:----:|:----:|
-|[支持语言](https://dtm.pub/other/opensource.html#lang) |Go、c#、Java、python、php...|Java|dtm可轻松接入一门新语言|
-|[存储引擎](https://dtm.pub/other/opensource.html#store) |支持数据库、Redis、Mongo等|数据库||
-|[异常处理](https://dtm.pub/other/opensource.html#exception)| 子事务屏障自动处理 |手动处理 |dtm解决了幂等、悬挂、空补偿|
-|[SAGA事务](https://dtm.pub/other/opensource.html#saga) |极简易用 |复杂状态机 ||
-|[二阶段消息](https://dtm.pub/other/opensource.html#msg)|✓|✗|最简消息最终一致性架构|
-|[TCC事务](https://dtm.pub/other/opensource.html#tcc)| ✓|✓||
-|[XA事务](https://dtm.pub/other/opensource.html#xa)|✓|✓||
-|[AT事务](https://dtm.pub/other/opensource.html#at)|建议使用XA|✓|AT与XA类似,但有脏回滚|
-|[单服务多数据源](https://dtm.pub/other/opensource.html#multidb)|✓|✗||
-|[通信协议](https://dtm.pub/other/opensource.html#protocol)|HTTP、gRPC、go-zero|dubbo等协议|dtm对云原生更加友好|
+如果贵公司也已使用 dtm,欢迎在 [登记地址](https://github.com/dtm-labs/dtm/issues/7) 登记,仅仅为了推广,不做其它用途。
-从上面对比的特性来看,dtm在许多方面都具备很大的优势。如果考虑多语言支持、多存储引擎支持,那么dtm毫无疑问是您的首选
+## 特性
+* 支持多种语言:支持Go、Java、PHP、C#、Python、Nodejs 各种语言的SDK
+* 支持多种事务模式:SAGA、TCC、XA
+* 支持消息最终一致性:二阶段消息,比本地消息表更优雅的方案
+* 未支持 AT 事务模式,建议使用XA,详情参见[XA vs AT](https://dtm.pub/practice/at)
+* 支持多种数据库事务:Mysql、Redis、MongoDB、Postgres、TDSQL等
+* 支持多种存储引擎:Mysql(常用)、Redis(高性能)、MongoDB(规划中)
+* 支持多种微服务架构:[go-zero](https://github.com/zeromicro/go-zero)、go-kratos/kratos、polarismesh/polaris
+* 支持高可用,易水平扩展
-详细的对比可以点击特性中的链接,跳到相关文档
+## 应用场景:
+DTM 可以应用于大量的场景下的数据一致性问题,以下是几个常见场景
+* [缓存管理](https://dtm.pub/app/cache.html):彻底保证缓存最终一致及强一致
+* [秒杀扣库存](https://dtm.pub/app/flash.html):极端情况下,也能保证Redis中精准的库存,和最终创建的订单完全一致,无需手动调整
+* [非单体的订单系统](https://dtm.pub/app/order.html): 大幅简化架构
+* [事件发布/订阅](https://dtm.pub/practice/msg.html):更好的发件箱模式
## [性能测试报告](https://dtm.pub/other/performance.html)
@@ -65,12 +45,6 @@ DTM是一款变革性的分布式事务框架,提供了傻瓜式的使用方
## [各语言客户端及示例](https://dtm.pub/ref/sdk.html#go)
-## 微服务框架支持
-- [go-zero](https://github.com/zeromicro/go-zero):一开源就非常火爆的微服务框架,首家接入dtm的微服务框架。感谢go-zero作者[kevwan](https://github.com/kevwan)的大力支持
-- [kratos](https://github.com/go-kratos/kratos):这是bilibili开源的一个微服务框架。感谢[lei liu](https://github.com/Leizhengzi)的贡献
-- [polaris](https://github.com/polarismesh/polaris): 腾讯开源的注册发现组件,以及在其上构建的微服务框架。感谢腾讯同学[ychensha](https://github.com/ychensha)的PR
-- 其他:看用户需求量,择机接入,参见[微服务支持](https://dtm.pub/ref/proto.html)
-
## 快速开始
如果您不是Go语言,可以跳转[各语言客户端及示例](https://dtm.pub/ref/sdk.html#go),里面有相关的快速开始示例
@@ -100,7 +74,7 @@ go run main.go
req := &gin.H{"amount": 30} // 微服务的载荷
// DtmServer为DTM服务的地址,是一个url
DtmServer := "http://localhost:36789/api/dtmsvr"
- saga := dtmcli.NewSaga(DtmServer, dtmcli.MustGenGid(DtmServer)).
+ saga := dtmcli.NewSaga(DtmServer, shortuuid.New()).
// 添加一个TransOut的子事务,正向操作为url: qsBusi+"/TransOut", 补偿操作为url: qsBusi+"/TransOutCom"
Add(qsBusi+"/TransOut", qsBusi+"/TransOutCom", req).
// 添加一个TransIn的子事务,正向操作为url: qsBusi+"/TransIn", 补偿操作为url: qsBusi+"/TransInCom"
@@ -137,10 +111,11 @@ go run main.go
上述示例主要演示了分布式事务的流程,更多的内容,包括如何与实际的数据库对接,如何做补偿,如何做回滚等实际的例子,请参考[dtm-labs/dtm-examples](https://github.com/dtm-labs/dtm-examples)
## 联系我们
-### 公众号
-dtm官方公众号:分布式事务,大量干货分享,以及dtm的最新消息
-### 交流群
-请加 yedf2008 好友或者扫码加好友,验证回复 dtm 按照指引进群
+### 微信交流群
+
+如果您希望更快的获得反馈,或者更多的了解其他用户在使用过程中的各种反馈,欢迎加入我们的微信交流群
+
+请加作者的微信 yedf2008 好友或者扫码加好友,备注 `dtm` 按照指引进群

diff --git a/helper/README-en.md b/helper/README-en.md
index 5e49007..740ae92 100644
--- a/helper/README-en.md
+++ b/helper/README-en.md
@@ -17,11 +17,13 @@ DTM is a distributed transaction framework which provides cross-service eventual
## Who's using DTM (partial)
-[Tencent](https://www.tencent.com/)
+[Tencent](https://en.dtm.pub/other/using.html#tencent)
-[Bytedance](https://www.bytedance.com/)
+[Bytedance](https://en.dtm.pub/other/using.html#bytedance)
-[Ivydad](https://ivydad.com)
+[Ivydad](https://en.dtm.pub/other/using.html#ivydad)
+
+[More](https://en.dtm.pub/other/using.html)
## [Cook Book](https://en.dtm.pub)
@@ -54,7 +56,7 @@ go run main.go
DtmServer := "http://localhost:36789/api/dtmsvr"
req := &gin.H{"amount": 30} // micro-service payload
// DtmServer is the address of DTM micro-service
- saga := dtmcli.NewSaga(DtmServer, dtmcli.MustGenGid(DtmServer)).
+ saga := dtmcli.NewSaga(DtmServer, shortuuid.New()).
// add a TransOut subtraction,forward operation with url: qsBusi+"/TransOut", reverse compensation operation with url: qsBusi+"/TransOutCom"
Add(qsBusi+"/TransOut", qsBusi+"/TransOutCom", req).
// add a TransIn subtraction, forward operation with url: qsBusi+"/TransIn", reverse compensation operation with url: qsBusi+"/TransInCom"
diff --git a/helper/bench/svr/http.go b/helper/bench/svr/http.go
index 0c61c5a..5a8b883 100644
--- a/helper/bench/svr/http.go
+++ b/helper/bench/svr/http.go
@@ -53,7 +53,7 @@ func reloadData() {
db := pdbGet()
tables := []string{"dtm_busi.user_account", "dtm_busi.user_account_log", "dtm.trans_global", "dtm.trans_branch_op", "dtm_barrier.barrier"}
for _, t := range tables {
- _, err := dtmimp.DBExec(db, fmt.Sprintf("truncate %s", t))
+ _, err := dtmimp.DBExec(busi.BusiConf.Driver, db, fmt.Sprintf("truncate %s", t))
logger.FatalIfError(err)
}
s := "insert ignore into dtm_busi.user_account(user_id, balance) values "
@@ -61,7 +61,7 @@ func reloadData() {
for i := 1; i <= total; i++ {
ss = append(ss, fmt.Sprintf("(%d, 1000000)", i))
}
- _, err := dtmimp.DBExec(db, s+strings.Join(ss, ","))
+ _, err := dtmimp.DBExec(busi.BusiConf.Driver, db, s+strings.Join(ss, ","))
logger.FatalIfError(err)
logger.Debugf("%d users inserted. used: %dms", total, time.Since(began).Milliseconds())
}
@@ -73,11 +73,11 @@ var sqls = 1
// PrepareBenchDB prepares db data for bench
func PrepareBenchDB() {
db := pdbGet()
- _, err := dtmimp.DBExec(db, "CREATE DATABASE if not exists dtm_busi")
+ _, err := dtmimp.DBExec(busi.BusiConf.Driver, db, "CREATE DATABASE if not exists dtm_busi")
logger.FatalIfError(err)
- _, err = dtmimp.DBExec(db, "drop table if exists dtm_busi.user_account_log")
+ _, err = dtmimp.DBExec(busi.BusiConf.Driver, db, "drop table if exists dtm_busi.user_account_log")
logger.FatalIfError(err)
- _, err = dtmimp.DBExec(db, `create table if not exists dtm_busi.user_account_log (
+ _, err = dtmimp.DBExec(busi.BusiConf.Driver, db, `create table if not exists dtm_busi.user_account_log (
id INT(11) AUTO_INCREMENT PRIMARY KEY,
user_id INT(11) NOT NULL,
delta DECIMAL(11, 2) not null,
@@ -111,10 +111,10 @@ func qsAdjustBalance(uid int, amount int, c *gin.Context) error { // nolint: unp
tb := dtmimp.TransBaseFromQuery(c.Request.URL.Query())
f := func(tx *sql.Tx) error {
for i := 0; i < sqls; i++ {
- _, err := dtmimp.DBExec(tx, "insert into dtm_busi.user_account_log(user_id, delta, gid, branch_id, op, reason) values(?,?,?,?,?,?)",
+ _, err := dtmimp.DBExec(busi.BusiConf.Driver, tx, "insert into dtm_busi.user_account_log(user_id, delta, gid, branch_id, op, reason) values(?,?,?,?,?,?)",
uid, amount, tb.Gid, c.Query("branch_id"), tb.TransType, fmt.Sprintf("inserted by dtm transaction %s %s", tb.Gid, c.Query("branch_id")))
logger.FatalIfError(err)
- _, err = dtmimp.DBExec(tx, "update dtm_busi.user_account set balance = balance + ?, update_time = now() where user_id = ?", amount, uid)
+ _, err = dtmimp.DBExec(busi.BusiConf.Driver, tx, "update dtm_busi.user_account set balance = balance + ?, update_time = now() where user_id = ?", amount, uid)
logger.FatalIfError(err)
}
return nil
@@ -122,7 +122,7 @@ func qsAdjustBalance(uid int, amount int, c *gin.Context) error { // nolint: unp
if strings.Contains(mode, "barrier") {
barrier, err := dtmcli.BarrierFromQuery(c.Request.URL.Query())
logger.FatalIfError(err)
- err = barrier.Call(txGet(), f)
+ err = barrier.CallWithDB(pdbGet(), f)
logger.FatalIfError(err)
} else {
tx := txGet()
diff --git a/helper/compose.cloud.yml b/helper/compose.cloud.yml
deleted file mode 100644
index 641adf9..0000000
--- a/helper/compose.cloud.yml
+++ /dev/null
@@ -1,28 +0,0 @@
-version: '3.3'
-services:
- api:
- build: ..
- volumes:
- - /etc/localtime:/etc/localtime:ro
- - /etc/timezone:/etc/timezone:ro
- - ..:/app/dtm
- extra_hosts:
- - 'host.docker.internal:host-gateway'
- environment:
- IS_DOCKER: 1
- ports:
- - '9080:8080'
- mysql:
- image: 'mysql:5.7'
- volumes:
- - /etc/localtime:/etc/localtime:ro
- - /etc/timezone:/etc/timezone:ro
- environment:
- MYSQL_ALLOW_EMPTY_PASSWORD: 1
- command:
- [
- '--character-set-server=utf8mb4',
- '--collation-server=utf8mb4_unicode_ci',
- ]
- ports:
- - '3306:3306'
diff --git a/helper/compose.mysql.yml b/helper/compose.mysql.yml
deleted file mode 100644
index 0c5ec71..0000000
--- a/helper/compose.mysql.yml
+++ /dev/null
@@ -1,16 +0,0 @@
-version: '3.3'
-services:
- mysql:
- image: 'mysql:5.7'
- volumes:
- - /etc/localtime:/etc/localtime:ro
- - /etc/timezone:/etc/timezone:ro
- environment:
- MYSQL_ALLOW_EMPTY_PASSWORD: 1
- command:
- [
- '--character-set-server=utf8mb4',
- '--collation-server=utf8mb4_unicode_ci',
- ]
- ports:
- - '3306:3306'
diff --git a/helper/compose.postgres.yml b/helper/compose.postgres.yml
deleted file mode 100644
index dc80e61..0000000
--- a/helper/compose.postgres.yml
+++ /dev/null
@@ -1,13 +0,0 @@
-version: '3.3'
-services:
- postgres:
- image: 'postgres:13'
- command: postgres --max_prepared_transactions=1000
- volumes:
- - /etc/localtime:/etc/localtime:ro
- - /etc/timezone:/etc/timezone:ro
- environment:
- POSTGRES_PASSWORD: mysecretpassword
-
- ports:
- - '5432:5432'
diff --git a/helper/compose.store.yml b/helper/compose.store.yml
index 4053807..0fb4707 100644
--- a/helper/compose.store.yml
+++ b/helper/compose.store.yml
@@ -22,6 +22,7 @@ services:
- /etc/timezone:/etc/timezone:ro
environment:
POSTGRES_PASSWORD: mysecretpassword
+ POSTGRES_DB: dtm
ports:
- '5432:5432'
diff --git a/helper/golint.sh b/helper/golint.sh
index 6c4b568..71f1817 100644
--- a/helper/golint.sh
+++ b/helper/golint.sh
@@ -1,4 +1,4 @@
set -x
-curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s -- -b $(go env GOPATH)/bin v1.41.0
+curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.46.2
$(go env GOPATH)/bin/golangci-lint run
diff --git a/helper/test-cover.sh b/helper/test-cover.sh
index 13bd654..e490032 100755
--- a/helper/test-cover.sh
+++ b/helper/test-cover.sh
@@ -1,6 +1,6 @@
set -x
echo "" > coverage.txt
-for store in redis mysql boltdb; do
+for store in redis mysql boltdb postgres; do
for d in $(go list ./... | grep -v vendor); do
TEST_STORE=$store go test -covermode count -coverprofile=profile.out -coverpkg=github.com/dtm-labs/dtm/dtmcli,github.com/dtm-labs/dtm/dtmcli/dtmimp,github.com/dtm-labs/dtm/dtmcli/logger,github.com/dtm-labs/dtm/dtmgrpc,github.com/dtm-labs/dtm/dtmgrpc/dtmgimp,github.com/dtm-labs/dtm/dtmsvr,github.com/dtm-labs/dtm/dtmsvr/config,github.com/dtm-labs/dtm/dtmsvr/storage,github.com/dtm-labs/dtm/dtmsvr/storage/boltdb,github.com/dtm-labs/dtm/dtmsvr/storage/redis,github.com/dtm-labs/dtm/dtmsvr/storage/registry,github.com/dtm-labs/dtm/dtmsvr/storage/sql,github.com/dtm-labs/dtm/dtmutil -gcflags=-l $d || exit 1
if [ -f profile.out ]; then
diff --git a/main.go b/main.go
index 8b8a134..2dd51c2 100644
--- a/main.go
+++ b/main.go
@@ -7,12 +7,20 @@
package main
import (
+ "embed"
"fmt"
+ "io/fs"
+ "io/ioutil"
"net/http"
"net/http/httputil"
"net/url"
+ "os"
+ "os/signal"
+ "strings"
+ "syscall"
"github.com/dtm-labs/dtm/dtmcli/logger"
+ "github.com/dtm-labs/dtm/dtmsvr/config"
"github.com/dtm-labs/dtm/dtmsvr/entry"
_ "github.com/dtm-labs/dtm/dtmsvr/microservices"
"github.com/gin-gonic/gin"
@@ -22,23 +30,61 @@ import (
var Version string
func main() {
- app := entry.Main(&Version)
+ app, conf := entry.Main(&Version)
if app != nil {
- addDashboard(app)
- select {}
+ addAdmin(app, conf)
+ q := make(chan os.Signal, 1)
+ signal.Notify(q, syscall.SIGINT, syscall.SIGTERM)
+ <-q
+ logger.Infof("Shutdown dtm server...")
}
}
-func addDashboard(app *gin.Engine) {
- app.GET("/dashboard/*name", proxyDashboard)
- app.GET("/@vite/*name", proxyDashboard)
- app.GET("/node_modules/*name", proxyDashboard)
- app.GET("/src/*name", proxyDashboard)
- app.GET("/@id/*name", proxyDashboard)
+
+//go:embed admin/dist
+var admin embed.FS
+
+var target = ""
+
+func getSub(f1 fs.FS, sub string) fs.FS {
+ f2, err := fs.Sub(f1, sub)
+ logger.FatalIfError(err)
+ return f2
+}
+func addAdmin(app *gin.Engine, conf *config.Type) {
+ // for released dtm, serve admin from local files because the build output has been embed
+ // for testing users, proxy admin to target because the build output has not been embed
+ dist := getSub(admin, "admin/dist")
+ index, err := dist.Open("index.html")
+ if err == nil {
+ cont, err := ioutil.ReadAll(index)
+ logger.FatalIfError(err)
+ _ = index.Close()
+ sfile := string(cont)
+ renderIndex := func(c *gin.Context) {
+ c.Header("content-type", "text/html;charset=utf-8")
+ c.String(200, sfile)
+ }
+ app.StaticFS("/assets", http.FS(getSub(dist, "assets")))
+ app.GET("/admin/*name", renderIndex)
+ app.GET("/", renderIndex)
+ logger.Infof("admin is served from dir 'admin/dist/'")
+ } else {
+ app.GET("/", proxyAdmin)
+ app.GET("/assets/*name", proxyAdmin)
+ app.GET("/admin/*name", proxyAdmin)
+ lang := os.Getenv("LANG")
+ if strings.HasPrefix(lang, "zh_CN") {
+ target = "cn-admin.dtm.pub"
+ } else {
+ target = "admin.dtm.pub"
+ }
+ logger.Infof("admin is proxied to %s", target)
+ }
+ logger.Infof("admin is running at: http://localhost:%d", conf.HTTPPort)
}
-func proxyDashboard(c *gin.Context) {
+func proxyAdmin(c *gin.Context) {
- target := "127.0.0.1:5000"
u := &url.URL{}
u.Scheme = "http"
u.Host = target
@@ -49,7 +95,8 @@ func proxyDashboard(c *gin.Context) {
ret := fmt.Sprintf("http proxy error %v", err)
_, _ = rw.Write([]byte(ret))
}
- logger.Debugf("proxy dashboard to %s", target)
+ logger.Debugf("proxy admin to %s", target)
+ c.Request.Host = target
proxy.ServeHTTP(c.Writer, c.Request)
}
diff --git a/sqls/dtmsvr.storage.mysql.sql b/sqls/dtmsvr.storage.mysql.sql
index 283bb75..50e4f9a 100644
--- a/sqls/dtmsvr.storage.mysql.sql
+++ b/sqls/dtmsvr.storage.mysql.sql
@@ -19,6 +19,7 @@ CREATE TABLE if not EXISTS dtm.trans_global (
`next_cron_time` datetime default null comment 'next time to process this trans. for use of cron job',
`owner` varchar(128) not null default '' comment 'who is locking this trans',
`ext_data` TEXT comment 'extended data for this trans',
+ `rollback_reason` varchar(1024) DEFAULT '' COMMENT 'rollback reason for transaction',
PRIMARY KEY (`id`),
UNIQUE KEY `gid` (`gid`),
key `owner`(`owner`),
@@ -41,3 +42,15 @@ CREATE TABLE IF NOT EXISTS dtm.trans_branch_op (
PRIMARY KEY (`id`),
UNIQUE KEY `gid_uniq` (`gid`, `branch_id`, `op`)
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4;
+drop table IF EXISTS dtm.kv;
+CREATE TABLE IF NOT EXISTS dtm.kv (
+ `id` bigint(22) NOT NULL AUTO_INCREMENT,
+ `cat` varchar(45) NOT NULL COMMENT 'the category of this data',
+ `k` varchar(128) NOT NULL,
+ `v` TEXT,
+ `version` bigint(22) default 1 COMMENT 'version of the value',
+ create_time datetime default NULL,
+ update_time datetime DEFAULT NULL,
+ PRIMARY KEY (`id`),
+ UNIQUE key `uniq_k`(`cat`, `k`)
+) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4;
diff --git a/sqls/dtmsvr.storage.postgres.sql b/sqls/dtmsvr.storage.postgres.sql
index 32af57f..898de34 100644
--- a/sqls/dtmsvr.storage.postgres.sql
+++ b/sqls/dtmsvr.storage.postgres.sql
@@ -1,11 +1,8 @@
-CREATE SCHEMA if not EXISTS dtm
-/* SQLINES DEMO *** RACTER SET utf8mb4 */
-;
-drop table IF EXISTS dtm.trans_global;
--- SQLINES LICENSE FOR EVALUATION USE ONLY
-CREATE SEQUENCE if not EXISTS dtm.trans_global_seq;
-CREATE TABLE if not EXISTS dtm.trans_global (
- id bigint NOT NULL DEFAULT NEXTVAL ('dtm.trans_global_seq'),
+drop table IF EXISTS trans_global;
+
+CREATE SEQUENCE if not EXISTS trans_global_seq;
+CREATE TABLE if not EXISTS trans_global (
+ id bigint NOT NULL DEFAULT NEXTVAL ('trans_global_seq'),
gid varchar(128) NOT NULL,
trans_type varchar(45) not null,
status varchar(45) NOT NULL,
@@ -21,16 +18,17 @@ CREATE TABLE if not EXISTS dtm.trans_global (
next_cron_time timestamp(0) with time zone default null,
owner varchar(128) not null default '',
ext_data text,
+ rollback_reason varchar(1024) DEFAULT '',
PRIMARY KEY (id),
CONSTRAINT gid UNIQUE (gid)
);
-create index if not EXISTS owner on dtm.trans_global(owner);
-create index if not EXISTS status_next_cron_time on dtm.trans_global (status, next_cron_time);
-drop table IF EXISTS dtm.trans_branch_op;
--- SQLINES LICENSE FOR EVALUATION USE ONLY
-CREATE SEQUENCE if not EXISTS dtm.trans_branch_op_seq;
-CREATE TABLE IF NOT EXISTS dtm.trans_branch_op (
- id bigint NOT NULL DEFAULT NEXTVAL ('dtm.trans_branch_op_seq'),
+create index if not EXISTS owner on trans_global(owner);
+create index if not EXISTS status_next_cron_time on trans_global (status, next_cron_time);
+drop table IF EXISTS trans_branch_op;
+
+CREATE SEQUENCE if not EXISTS trans_branch_op_seq;
+CREATE TABLE IF NOT EXISTS trans_branch_op (
+ id bigint NOT NULL DEFAULT NEXTVAL ('trans_branch_op_seq'),
gid varchar(128) NOT NULL,
url varchar(1024) NOT NULL,
data TEXT,
@@ -44,4 +42,4 @@ CREATE TABLE IF NOT EXISTS dtm.trans_branch_op (
update_time timestamp(0) with time zone DEFAULT NULL,
PRIMARY KEY (id),
CONSTRAINT gid_branch_uniq UNIQUE (gid, branch_id, op)
-);
\ No newline at end of file
+);
diff --git a/sqls/dtmsvr.storage.tdsql.sql b/sqls/dtmsvr.storage.tdsql.sql
index ded809f..a24992c 100644
--- a/sqls/dtmsvr.storage.tdsql.sql
+++ b/sqls/dtmsvr.storage.tdsql.sql
@@ -19,6 +19,7 @@ CREATE TABLE if not EXISTS dtm.trans_global (
`next_cron_time` datetime default null comment 'next time to process this trans. for use of cron job',
`owner` varchar(128) not null default '' comment 'who is locking this trans',
`ext_data` TEXT comment 'extended data for this trans',
+ `rollback_reason` varchar(1024) DEFAULT '' COMMENT 'rollback reason for transaction',
PRIMARY KEY (`id`,`gid`),
UNIQUE KEY `id` (`id`,`gid`),
UNIQUE KEY `gid` (`gid`),
diff --git a/test/api_test.go b/test/api_test.go
index ff3d5d6..e63fc27 100644
--- a/test/api_test.go
+++ b/test/api_test.go
@@ -18,6 +18,12 @@ import (
"github.com/stretchr/testify/assert"
)
+func TestAPIVersion(t *testing.T) {
+ resp, err := dtmimp.RestyClient.R().Get(dtmutil.DefaultHTTPServer + "/version")
+ assert.Nil(t, err)
+ assert.Equal(t, 200, resp.StatusCode())
+}
+
func TestAPIQuery(t *testing.T) {
gid := dtmimp.GetFuncName()
err := genMsg(gid).Submit()
diff --git a/test/base_test.go b/test/base_test.go
index 68ea359..3fbd05c 100644
--- a/test/base_test.go
+++ b/test/base_test.go
@@ -26,7 +26,7 @@ type BarrierModel struct {
}
// TableName gorm table name
-func (BarrierModel) TableName() string { return "dtm_barrier.barrier" }
+func (BarrierModel) TableName() string { return dtmimp.BarrierTableName }
func TestBaseSqlDB(t *testing.T) {
asserts := assert.New(t)
@@ -38,7 +38,7 @@ func TestBaseSqlDB(t *testing.T) {
Op: dtmimp.OpAction,
BarrierID: 1,
}
- db.Must().Exec("insert into dtm_barrier.barrier(trans_type, gid, branch_id, op, barrier_id, reason) values('saga', 'gid1', 'branch_id1', 'action', '01', 'saga')")
+ db.Must().Exec(fmt.Sprintf("insert into %s(trans_type, gid, branch_id, op, barrier_id, reason) values('saga', 'gid1', 'branch_id1', 'action', '01', 'saga')", dtmimp.BarrierTableName))
tx, err := db.ToSQLDB().Begin()
asserts.Nil(err)
err = barrier.Call(tx, func(tx *sql.Tx) error {
diff --git a/test/busi/barrier.go b/test/busi/barrier.go
index 7179e14..b80cb55 100644
--- a/test/busi/barrier.go
+++ b/test/busi/barrier.go
@@ -22,49 +22,49 @@ func init() {
setupFuncs["BarrierSetup"] = func(app *gin.Engine) {
app.POST(BusiAPI+"/SagaBTransIn", dtmutil.WrapHandler(func(c *gin.Context) interface{} {
barrier := MustBarrierFromGin(c)
- return barrier.Call(txGet(), func(tx *sql.Tx) error {
+ return barrier.CallWithDB(pdbGet(), func(tx *sql.Tx) error {
return SagaAdjustBalance(tx, TransInUID, reqFrom(c).Amount, reqFrom(c).TransInResult)
})
}))
app.POST(BusiAPI+"/SagaBTransInCom", dtmutil.WrapHandler(func(c *gin.Context) interface{} {
barrier := MustBarrierFromGin(c)
- return barrier.Call(txGet(), func(tx *sql.Tx) error {
+ return barrier.CallWithDB(pdbGet(), func(tx *sql.Tx) error {
return SagaAdjustBalance(tx, TransInUID, -reqFrom(c).Amount, "")
})
}))
app.POST(BusiAPI+"/SagaB2TransIn", dtmutil.WrapHandler(func(c *gin.Context) interface{} {
barrier := MustBarrierFromGin(c)
- err := barrier.Call(txGet(), func(tx *sql.Tx) error {
+ err := barrier.CallWithDB(pdbGet(), func(tx *sql.Tx) error {
return SagaAdjustBalance(tx, TransInUID, reqFrom(c).Amount/2, reqFrom(c).TransInResult)
})
if err != nil {
return err
}
- return barrier.Call(txGet(), func(tx *sql.Tx) error {
+ return barrier.CallWithDB(pdbGet(), func(tx *sql.Tx) error {
return SagaAdjustBalance(tx, TransInUID, reqFrom(c).Amount/2, reqFrom(c).TransInResult)
})
}))
app.POST(BusiAPI+"/SagaB2TransInCom", dtmutil.WrapHandler(func(c *gin.Context) interface{} {
barrier := MustBarrierFromGin(c)
- err := barrier.Call(txGet(), func(tx *sql.Tx) error {
+ err := barrier.CallWithDB(pdbGet(), func(tx *sql.Tx) error {
return SagaAdjustBalance(tx, TransInUID, -reqFrom(c).Amount/2, "")
})
if err != nil {
return err
}
- return barrier.Call(txGet(), func(tx *sql.Tx) error {
+ return barrier.CallWithDB(pdbGet(), func(tx *sql.Tx) error {
return SagaAdjustBalance(tx, TransInUID, -reqFrom(c).Amount, "")
})
}))
app.POST(BusiAPI+"/SagaBTransOut", dtmutil.WrapHandler(func(c *gin.Context) interface{} {
barrier := MustBarrierFromGin(c)
- return barrier.Call(txGet(), func(tx *sql.Tx) error {
+ return barrier.CallWithDB(pdbGet(), func(tx *sql.Tx) error {
return SagaAdjustBalance(tx, TransOutUID, -reqFrom(c).Amount, reqFrom(c).TransOutResult)
})
}))
app.POST(BusiAPI+"/SagaBTransOutCom", dtmutil.WrapHandler(func(c *gin.Context) interface{} {
barrier := MustBarrierFromGin(c)
- return barrier.Call(txGet(), func(tx *sql.Tx) error {
+ return barrier.CallWithDB(pdbGet(), func(tx *sql.Tx) error {
return SagaAdjustBalance(tx, TransOutUID, reqFrom(c).Amount, "")
})
}))
@@ -82,17 +82,17 @@ func init() {
if req.TransInResult != "" {
return dtmcli.String2DtmError(req.TransInResult)
}
- return MustBarrierFromGin(c).Call(txGet(), func(tx *sql.Tx) error {
+ return MustBarrierFromGin(c).CallWithDB(pdbGet(), func(tx *sql.Tx) error {
return tccAdjustTrading(tx, TransInUID, req.Amount)
})
}))
app.POST(BusiAPI+"/TccBTransInConfirm", dtmutil.WrapHandler(func(c *gin.Context) interface{} {
- return MustBarrierFromGin(c).Call(txGet(), func(tx *sql.Tx) error {
+ return MustBarrierFromGin(c).CallWithDB(pdbGet(), func(tx *sql.Tx) error {
return tccAdjustBalance(tx, TransInUID, reqFrom(c).Amount)
})
}))
app.POST(BusiAPI+"/TccBTransInCancel", dtmutil.WrapHandler(func(c *gin.Context) interface{} {
- return MustBarrierFromGin(c).Call(txGet(), func(tx *sql.Tx) error {
+ return MustBarrierFromGin(c).CallWithDB(pdbGet(), func(tx *sql.Tx) error {
return tccAdjustTrading(tx, TransInUID, -reqFrom(c).Amount)
})
}))
@@ -170,7 +170,7 @@ func init() {
})
}
- return bb.Call(txGet(), func(tx *sql.Tx) error {
+ return bb.CallWithDB(pdbGet(), func(tx *sql.Tx) error {
return tccAdjustTrading(tx, TransOutUID, -req.Amount)
})
}))
@@ -178,7 +178,7 @@ func init() {
if reqFrom(c).Store == Redis || reqFrom(c).Store == Mongo {
return nil
}
- return MustBarrierFromGin(c).Call(txGet(), func(tx *sql.Tx) error {
+ return MustBarrierFromGin(c).CallWithDB(pdbGet(), func(tx *sql.Tx) error {
return tccAdjustBalance(tx, TransOutUID, -reqFrom(c).Amount)
})
}))
@@ -198,7 +198,7 @@ func TccBarrierTransOutCancel(c *gin.Context) interface{} {
return SagaMongoAdjustBalance(sc, sc.Client(), TransOutUID, reqFrom(c).Amount, "")
})
}
- return bb.Call(txGet(), func(tx *sql.Tx) error {
+ return bb.CallWithDB(pdbGet(), func(tx *sql.Tx) error {
return tccAdjustTrading(tx, TransOutUID, reqFrom(c).Amount)
})
}
@@ -212,21 +212,21 @@ func (s *busiServer) TransInBSaga(ctx context.Context, in *BusiReq) (*emptypb.Em
func (s *busiServer) TransOutBSaga(ctx context.Context, in *BusiReq) (*emptypb.Empty, error) {
barrier := MustBarrierFromGrpc(ctx)
- return &emptypb.Empty{}, barrier.Call(txGet(), func(tx *sql.Tx) error {
+ return &emptypb.Empty{}, barrier.CallWithDB(pdbGet(), func(tx *sql.Tx) error {
return sagaGrpcAdjustBalance(tx, TransOutUID, -in.Amount, in.TransOutResult)
})
}
func (s *busiServer) TransInRevertBSaga(ctx context.Context, in *BusiReq) (*emptypb.Empty, error) {
barrier := MustBarrierFromGrpc(ctx)
- return &emptypb.Empty{}, barrier.Call(txGet(), func(tx *sql.Tx) error {
+ return &emptypb.Empty{}, barrier.CallWithDB(pdbGet(), func(tx *sql.Tx) error {
return sagaGrpcAdjustBalance(tx, TransInUID, -in.Amount, "")
})
}
func (s *busiServer) TransOutRevertBSaga(ctx context.Context, in *BusiReq) (*emptypb.Empty, error) {
barrier := MustBarrierFromGrpc(ctx)
- return &emptypb.Empty{}, barrier.Call(txGet(), func(tx *sql.Tx) error {
+ return &emptypb.Empty{}, barrier.CallWithDB(pdbGet(), func(tx *sql.Tx) error {
return sagaGrpcAdjustBalance(tx, TransOutUID, in.Amount, "")
})
}
diff --git a/test/busi/base_http.go b/test/busi/base_http.go
index e2609bf..c2bf076 100644
--- a/test/busi/base_http.go
+++ b/test/busi/base_http.go
@@ -69,7 +69,8 @@ func BaseAppStartup() *gin.Engine {
}
logger.Debugf("Starting busi at: %d", BusiPort)
go func() {
- _ = app.Run(fmt.Sprintf(":%d", BusiPort))
+ err := app.Run(fmt.Sprintf(":%d", BusiPort))
+ dtmimp.FatalIfError(err)
}()
return app
}
@@ -140,7 +141,7 @@ func BaseAddRoute(app *gin.Engine) {
}))
app.POST(BusiAPI+"/TransOutXa", dtmutil.WrapHandler(func(c *gin.Context) interface{} {
return dtmcli.XaLocalTransaction(c.Request.URL.Query(), BusiConf, func(db *sql.DB, xa *dtmcli.Xa) error {
- return SagaAdjustBalance(db, TransOutUID, reqFrom(c).Amount, reqFrom(c).TransOutResult)
+ return SagaAdjustBalance(db, TransOutUID, -reqFrom(c).Amount, reqFrom(c).TransOutResult)
})
}))
app.POST(BusiAPI+"/TransOutTimeout", dtmutil.WrapHandler(func(c *gin.Context) interface{} {
diff --git a/test/busi/base_types.go b/test/busi/base_types.go
index 541c2cb..0d4171d 100644
--- a/test/busi/base_types.go
+++ b/test/busi/base_types.go
@@ -142,6 +142,7 @@ type mainSwitchType struct {
QueryPreparedResult AutoEmptyString
NextResult AutoEmptyString
JrpcResult AutoEmptyString
+ FailureReason AutoEmptyString
}
// MainSwitch controls busi success or fail
diff --git a/test/busi/busi.go b/test/busi/busi.go
index c4026ed..81c9c9e 100644
--- a/test/busi/busi.go
+++ b/test/busi/busi.go
@@ -34,7 +34,7 @@ func handleGrpcBusiness(in *BusiReq, result1 string, result2 string, busi string
if res == dtmcli.ResultSuccess {
return nil
} else if res == dtmcli.ResultFailure {
- return status.New(codes.Aborted, dtmcli.ResultFailure).Err()
+ return status.New(codes.Aborted, fmt.Sprintf("reason:%s", MainSwitch.FailureReason.Fetch())).Err()
} else if res == dtmcli.ResultOngoing {
return status.New(codes.FailedPrecondition, dtmcli.ResultOngoing).Err()
}
@@ -48,6 +48,9 @@ func handleGeneralBusiness(c *gin.Context, result1 string, result2 string, busi
if res == "ERROR" {
return errors.New("ERROR from user")
}
+ if res == dtmimp.ResultFailure {
+ return fmt.Errorf("reason:%s. %w", MainSwitch.FailureReason.Fetch(), dtmimp.ErrFailure)
+ }
return dtmcli.String2DtmError(res)
}
@@ -66,7 +69,7 @@ func sagaGrpcAdjustBalance(db dtmcli.DB, uid int, amount int64, result string) e
if result == dtmcli.ResultFailure {
return status.New(codes.Aborted, dtmcli.ResultFailure).Err()
}
- _, err := dtmimp.DBExec(db, "update dtm_busi.user_account set balance = balance + ? where user_id = ?", amount, uid)
+ _, err := dtmimp.DBExec(BusiConf.Driver, db, "update dtm_busi.user_account set balance = balance + ? where user_id = ?", amount, uid)
return err
}
@@ -75,7 +78,7 @@ func SagaAdjustBalance(db dtmcli.DB, uid int, amount int, result string) error {
if strings.Contains(result, dtmcli.ResultFailure) {
return dtmcli.ErrFailure
}
- _, err := dtmimp.DBExec(db, "update dtm_busi.user_account set balance = balance + ? where user_id = ?", amount, uid)
+ _, err := dtmimp.DBExec(BusiConf.Driver, db, "update dtm_busi.user_account set balance = balance + ? where user_id = ?", amount, uid)
return err
}
@@ -102,12 +105,12 @@ func SagaMongoAdjustBalance(ctx context.Context, mc *mongo.Client, uid int, amou
return fmt.Errorf("balance not enough %w", dtmcli.ErrFailure)
}
return nil
-
}
func tccAdjustTrading(db dtmcli.DB, uid int, amount int) error {
- affected, err := dtmimp.DBExec(db, `update dtm_busi.user_account set trading_balance=trading_balance+?
- where user_id=? and trading_balance + ? + balance >= 0`, amount, uid, amount)
+ affected, err := dtmimp.DBExec(BusiConf.Driver, db, `update dtm_busi.user_account
+ set trading_balance=trading_balance+?
+ where user_id=? and trading_balance + ? + balance >= 0`, amount, uid, amount)
if err == nil && affected == 0 {
return fmt.Errorf("update error, maybe balance not enough")
}
@@ -115,8 +118,9 @@ func tccAdjustTrading(db dtmcli.DB, uid int, amount int) error {
}
func tccAdjustBalance(db dtmcli.DB, uid int, amount int) error {
- affected, err := dtmimp.DBExec(db, `update dtm_busi.user_account set trading_balance=trading_balance-?,
- balance=balance+? where user_id=?`, amount, amount, uid)
+ affected, err := dtmimp.DBExec(BusiConf.Driver, db, `update dtm_busi.user_account
+ set trading_balance=trading_balance-?,
+ balance=balance+? where user_id=?`, amount, amount, uid)
if err == nil && affected == 0 {
return fmt.Errorf("update user_account 0 rows")
}
diff --git a/test/busi/quick_start.go b/test/busi/quick_start.go
index 6d57af5..2f33d72 100644
--- a/test/busi/quick_start.go
+++ b/test/busi/quick_start.go
@@ -7,6 +7,7 @@ import (
"github.com/dtm-labs/dtm/dtmcli"
"github.com/gin-gonic/gin"
+ "github.com/lithammer/shortuuid/v3"
)
// busi address
@@ -59,7 +60,7 @@ const dtmServer = "http://localhost:36789/api/dtmsvr"
func QsFireRequest() string {
req := &gin.H{"amount": 30} // load of micro-service
// DtmServer is the url of dtm
- saga := dtmcli.NewSaga(dtmServer, dtmcli.MustGenGid(dtmServer)).
+ saga := dtmcli.NewSaga(dtmServer, shortuuid.New()).
// add a TransOut subtraction,forward operation with url: qsBusi+"/TransOut", reverse compensation operation with url: qsBusi+"/TransOutCompensate"
Add(qsBusi+"/TransOut", qsBusi+"/TransOutCompensate", req).
// add a TransIn subtraction, forward operation with url: qsBusi+"/TransIn", reverse compensation operation with url: qsBusi+"/TransInCompensate"
diff --git a/test/common_test.go b/test/common_test.go
index 2a9b917..a28a144 100644
--- a/test/common_test.go
+++ b/test/common_test.go
@@ -33,12 +33,12 @@ func testSql(t *testing.T) {
func testDbAlone(t *testing.T) {
db, err := dtmimp.StandaloneDB(conf.Store.GetDBConf())
assert.Nil(t, err)
- _, err = dtmimp.DBExec(db, "select 1")
+ _, err = dtmimp.DBExec(conf.Store.Driver, db, "select 1")
assert.Equal(t, nil, err)
- _, err = dtmimp.DBExec(db, "")
+ _, err = dtmimp.DBExec(conf.Store.Driver, db, "")
assert.Equal(t, nil, err)
db.Close()
- _, err = dtmimp.DBExec(db, "select 1")
+ _, err = dtmimp.DBExec(conf.Store.Driver, db, "select 1")
assert.NotEqual(t, nil, err)
}
diff --git a/test/dtmsvr_test.go b/test/dtmsvr_test.go
index 345bebe..273fe36 100644
--- a/test/dtmsvr_test.go
+++ b/test/dtmsvr_test.go
@@ -26,6 +26,10 @@ func getTransStatus(gid string) string {
return dtmsvr.GetTransGlobal(gid).Status
}
+func getTrans(gid string) *dtmsvr.TransGlobal {
+ return dtmsvr.GetTransGlobal(gid)
+}
+
func getBranchesStatus(gid string) []string {
branches := dtmsvr.GetStore().FindBranches(gid)
status := []string{}
diff --git a/test/main_test.go b/test/main_test.go
index 4f17d73..a9f48d8 100644
--- a/test/main_test.go
+++ b/test/main_test.go
@@ -30,7 +30,6 @@ func exitIf(code int) {
func TestMain(m *testing.M) {
config.MustLoadConfig("")
logger.InitLog("debug")
- dtmcli.SetCurrentDBType(busi.BusiConf.Driver)
dtmsvr.TransProcessedTestChan = make(chan string, 1)
dtmsvr.NowForwardDuration = 0 * time.Second
dtmsvr.CronForwardDuration = 180 * time.Second
@@ -41,24 +40,31 @@ func TestMain(m *testing.M) {
dtmcli.GetRestyClient().OnAfterResponse(func(c *resty.Client, resp *resty.Response) error { return nil })
tenv := os.Getenv("TEST_STORE")
+ conf.Store.Host = "localhost"
+ conf.Store.Driver = tenv
if tenv == "boltdb" {
- conf.Store.Driver = "boltdb"
- } else if tenv == "mysql" {
- conf.Store.Driver = "mysql"
- conf.Store.Host = "localhost"
+ } else if tenv == config.Mysql {
conf.Store.Port = 3306
conf.Store.User = "root"
conf.Store.Password = ""
- } else {
- conf.Store.Driver = "redis"
- conf.Store.Host = "localhost"
+ } else if tenv == config.Postgres {
+ conf.Store.Port = 5432
+ conf.Store.User = "postgres"
+ conf.Store.Password = "mysecretpassword"
+ } else if tenv == config.Redis {
conf.Store.User = ""
conf.Store.Password = ""
conf.Store.Port = 6379
}
+ conf.Store.Db = ""
registry.WaitStoreUp()
dtmsvr.PopulateDB(false)
+ conf.Store.Db = "dtm" // after populateDB, set current db to dtm
+ if tenv == "postgres" {
+ busi.BusiConf = conf.Store.GetDBConf()
+ dtmcli.SetCurrentDBType(tenv)
+ }
go dtmsvr.StartSvr()
busi.PopulateDB(false)
diff --git a/test/saga_grpc_test.go b/test/saga_grpc_test.go
index 94f1732..9a98d06 100644
--- a/test/saga_grpc_test.go
+++ b/test/saga_grpc_test.go
@@ -28,6 +28,7 @@ func TestSagaGrpcNormal(t *testing.T) {
func TestSagaGrpcRollback(t *testing.T) {
gid := dtmimp.GetFuncName()
saga := genSagaGrpc(gid, false, true)
+ busi.MainSwitch.FailureReason.SetOnce("Insufficient balance")
busi.MainSwitch.TransOutRevertResult.SetOnce(dtmcli.ResultOngoing)
saga.Submit()
waitTransProcessed(saga.Gid)
@@ -35,6 +36,7 @@ func TestSagaGrpcRollback(t *testing.T) {
cronTransOnce(t, gid)
assert.Equal(t, StatusFailed, getTransStatus(saga.Gid))
assert.Equal(t, []string{StatusSucceed, StatusSucceed, StatusSucceed, StatusFailed}, getBranchesStatus(saga.Gid))
+ assert.Equal(t, "url:localhost:58081/busi.Busi/TransIn return failed: reason:Insufficient balance. FAILURE", getTrans(saga.Gid).RollbackReason)
}
func TestSagaGrpcCurrent(t *testing.T) {
diff --git a/test/saga_options_test.go b/test/saga_options_test.go
index 6134ee7..557ab1d 100644
--- a/test/saga_options_test.go
+++ b/test/saga_options_test.go
@@ -56,6 +56,8 @@ func TestSagaOptionsTimeout(t *testing.T) {
cronTransOnceForwardNow(t, gid, 3600)
assert.Equal(t, StatusFailed, getTransStatus(saga.Gid))
assert.Equal(t, []string{StatusSucceed, StatusPrepared, StatusPrepared, StatusPrepared}, getBranchesStatus(saga.Gid))
+ assert.Regexp(t, `^Timeout after \d+ seconds$`, getTrans(gid).RollbackReason)
+
}
func TestSagaGlobalTransWithRequestTimeout(t *testing.T) {
diff --git a/test/saga_test.go b/test/saga_test.go
index d7b9ad7..f536a4c 100644
--- a/test/saga_test.go
+++ b/test/saga_test.go
@@ -22,15 +22,18 @@ func TestSagaNormal(t *testing.T) {
waitTransProcessed(saga.Gid)
assert.Equal(t, []string{StatusPrepared, StatusSucceed, StatusPrepared, StatusSucceed}, getBranchesStatus(saga.Gid))
assert.Equal(t, StatusSucceed, getTransStatus(saga.Gid))
+ assert.Equal(t, "", getTrans(saga.Gid).RollbackReason)
}
func TestSagaRollback(t *testing.T) {
saga := genSaga(dtmimp.GetFuncName(), false, true)
+ busi.MainSwitch.FailureReason.SetOnce("Insufficient balance")
err := saga.Submit()
assert.Nil(t, err)
waitTransProcessed(saga.Gid)
assert.Equal(t, []string{StatusSucceed, StatusSucceed, StatusSucceed, StatusFailed}, getBranchesStatus(saga.Gid))
assert.Equal(t, StatusFailed, getTransStatus(saga.Gid))
+ assert.Equal(t, "url:http://localhost:8081/api/busi/TransIn return failed: {\"error\":\"reason:Insufficient balance. FAILURE\"}. FAILURE", getTrans(saga.Gid).RollbackReason)
}
func TestSagaOngoingSucceed(t *testing.T) {
@@ -44,6 +47,7 @@ func TestSagaOngoingSucceed(t *testing.T) {
cronTransOnce(t, gid)
assert.Equal(t, []string{StatusPrepared, StatusSucceed, StatusPrepared, StatusSucceed}, getBranchesStatus(saga.Gid))
assert.Equal(t, StatusSucceed, getTransStatus(saga.Gid))
+ assert.Equal(t, "", getTrans(saga.Gid).RollbackReason)
}
func TestSagaFailed(t *testing.T) {
diff --git a/test/store_test.go b/test/store_test.go
index b9bb31e..4cc3c00 100644
--- a/test/store_test.go
+++ b/test/store_test.go
@@ -100,73 +100,73 @@ func TestStoreResetCronTime(t *testing.T) {
})
}
-func testStoreResetCronTime(t *testing.T, funcName string, restCronHandler func(expire int64, limit int64) (int64, bool, error)) {
+func testStoreResetCronTime(t *testing.T, funcName string, resetCronHandler func(expire int64, limit int64) (int64, bool, error)) {
s := registry.GetStore()
- var restTimeTimeout, lockExpireIn, limit, i int64
- restTimeTimeout = 100 //The time that will be ResetCronTime
- lockExpireIn = 2 //The time that will be LockOneGlobalTrans
- limit = 10 // rest limit
+ var afterSeconds, lockExpireIn, limit, i int64
+ afterSeconds = 100
+ lockExpireIn = 2
+ limit = 10
// Will be reset
for i = 0; i < limit; i++ {
gid := funcName + fmt.Sprintf("%d", i)
- _, _ = initTransGlobalByNextCronTime(gid, time.Now().Add(time.Duration(restTimeTimeout+10)*time.Second))
+ _, _ = initTransGlobalByNextCronTime(gid, time.Now().Add(time.Duration(afterSeconds+10)*time.Second))
}
// Will not be reset
gid := funcName + fmt.Sprintf("%d", 10)
- _, _ = initTransGlobalByNextCronTime(gid, time.Now().Add(time.Duration(restTimeTimeout-10)*time.Second))
+ _, _ = initTransGlobalByNextCronTime(gid, time.Now().Add(time.Duration(afterSeconds-10)*time.Second))
- // Not Fount
+ // Not Found
g := s.LockOneGlobalTrans(time.Duration(lockExpireIn) * time.Second)
assert.Nil(t, g)
- // Rest limit-1 count
- succeedCount, hasRemaining, err := restCronHandler(restTimeTimeout, limit-1)
+ // Reset limit-1 count
+ succeedCount, hasRemaining, err := resetCronHandler(afterSeconds, limit-1)
assert.Equal(t, hasRemaining, true)
assert.Equal(t, succeedCount, limit-1)
assert.Nil(t, err)
- // Fount limit-1 count
+ // Found limit-1 count
for i = 0; i < limit-1; i++ {
g = s.LockOneGlobalTrans(time.Duration(lockExpireIn) * time.Second)
assert.NotNil(t, g)
s.ChangeGlobalStatus(g, "succeed", []string{}, true)
}
- // Not Fount
+ // Not Found
g = s.LockOneGlobalTrans(time.Duration(lockExpireIn) * time.Second)
assert.Nil(t, g)
- // Rest 1 count
- succeedCount, hasRemaining, err = restCronHandler(restTimeTimeout, limit)
+ // Reset 1 count
+ succeedCount, hasRemaining, err = resetCronHandler(afterSeconds, limit)
assert.Equal(t, hasRemaining, false)
assert.Equal(t, succeedCount, int64(1))
assert.Nil(t, err)
- // Fount 1 count
+ // Found 1 count
g = s.LockOneGlobalTrans(time.Duration(lockExpireIn) * time.Second)
assert.NotNil(t, g)
s.ChangeGlobalStatus(g, "succeed", []string{}, true)
- // Not Fount
+ // Not Found
g = s.LockOneGlobalTrans(time.Duration(lockExpireIn) * time.Second)
assert.Nil(t, g)
- // reduce the restTimeTimeout, Rest 1 count
- succeedCount, hasRemaining, err = restCronHandler(restTimeTimeout-12, limit)
+ // reduce the resetTimeTimeout, Reset 1 count
+ succeedCount, hasRemaining, err = resetCronHandler(afterSeconds-12, limit)
assert.Equal(t, hasRemaining, false)
assert.Equal(t, succeedCount, int64(1))
assert.Nil(t, err)
- // Fount 1 count
+ // Found 1 count
g = s.LockOneGlobalTrans(time.Duration(lockExpireIn) * time.Second)
assert.NotNil(t, g)
s.ChangeGlobalStatus(g, "succeed", []string{}, true)
- // Not Fount
+ // Not Found
g = s.LockOneGlobalTrans(time.Duration(lockExpireIn) * time.Second)
assert.Nil(t, g)
- // Not Fount
- succeedCount, hasRemaining, err = restCronHandler(restTimeTimeout-12, limit)
+ // Not Found
+ succeedCount, hasRemaining, err = resetCronHandler(afterSeconds-12, limit)
assert.Equal(t, hasRemaining, false)
assert.Equal(t, succeedCount, int64(0))
assert.Nil(t, err)
diff --git a/test/tcc_test.go b/test/tcc_test.go
index 60fccd2..f4f229d 100644
--- a/test/tcc_test.go
+++ b/test/tcc_test.go
@@ -67,6 +67,7 @@ func TestTccTimeout(t *testing.T) {
})
assert.Error(t, err)
assert.Equal(t, StatusFailed, getTransStatus(gid))
+ assert.Regexp(t, `^Timeout after \d+ seconds$`, getTrans(gid).RollbackReason)
assert.Equal(t, []string{StatusSucceed, StatusPrepared}, getBranchesStatus(gid))
}
diff --git a/test/xa_cover_test.go b/test/xa_cover_test.go
index 6836582..8c602ae 100644
--- a/test/xa_cover_test.go
+++ b/test/xa_cover_test.go
@@ -39,6 +39,9 @@ func TestXaCoverDTMError(t *testing.T) {
}
func TestXaCoverGidError(t *testing.T) {
+ if dtmimp.GetCurrentDBType() != dtmimp.DBTypeMysql {
+ return
+ }
gid := dtmimp.GetFuncName() + "-' '"
err := dtmcli.XaGlobalTransaction(DtmServer, gid, func(xa *dtmcli.Xa) (*resty.Response, error) {
req := busi.GenTransReq(30, false, false)
diff --git a/test/xa_test.go b/test/xa_test.go
index 4980a0a..a15c339 100644
--- a/test/xa_test.go
+++ b/test/xa_test.go
@@ -43,10 +43,10 @@ func TestXaDuplicate(t *testing.T) {
sdb, err := dtmimp.StandaloneDB(busi.BusiConf)
assert.Nil(t, err)
if dtmcli.GetCurrentDBType() == dtmcli.DBTypeMysql {
- _, err = dtmimp.DBExec(sdb, "xa recover")
+ _, err = dtmimp.DBExec(busi.BusiConf.Driver, sdb, "xa recover")
assert.Nil(t, err)
}
- _, err = dtmimp.DBExec(sdb, dtmimp.GetDBSpecial().GetXaSQL("commit", gid+"-01")) // simulate repeated request
+ _, err = dtmimp.DBExec(busi.BusiConf.Driver, sdb, dtmimp.GetDBSpecial(busi.BusiConf.Driver).GetXaSQL("commit", gid+"-01")) // simulate repeated request
assert.Nil(t, err)
return xa.CallBranch(req, busi.Busi+"/TransInXa")
})
@@ -94,6 +94,7 @@ func TestXaTimeout(t *testing.T) {
})
assert.Error(t, err)
assert.Equal(t, StatusFailed, getTransStatus(gid))
+ assert.Regexp(t, `^Timeout after \d+ seconds$`, getTrans(gid).RollbackReason)
assert.Equal(t, []string{}, getBranchesStatus(gid))
}