• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

uber / cadence / 01909e15-00cc-4a94-bf01-3784d6403d00

27 Jun 2024 01:09AM UTC coverage: 71.431% (-0.1%) from 71.557%
01909e15-00cc-4a94-bf01-3784d6403d00

push

buildkite

web-flow
Refactor/removing cross cluster feature (#6121)

## What changed?

This mostly* removes the cross-cluster feature.

## Background
The Cross-cluster feature was the ability to launch and interact with child workflows in another domain. It included the ability to start child workflows and signal them. The feature allowed child workflows to be launched in the target domain even if it was active in another region.

## Problems
The feature itself was something that very very few of our customers apparently needed, with very few customers interested in the problem of launching child workflows in another cluster, and zero who weren’t able to simply use an activity to make an RPC call to the other domain as one would with any normal workflow.
The feature-itself was quite resource intensive: It was pull-based; spinning up a polling stack which polled the other cluster for work, similar to the replication stack. This polling behaviour made the latency characteristics fairly unpredictable and used considerable DB resources, to the point that we just turned it off. The Uber/Cadence team resolved that were there sufficient demand for the feature in the future, a push based mechanism would probably be significantly preferable.
The feature itself added a nontrivial amount of complexity to the codebase in a few areas such as task processing and domain error handling which introduced difficult to understand bugs such as the child workflow dropping error #5919

Decision to deprecate and alternatives
As of releases June 2024, the feature will be removed. The Cadence team is not aware of any users of the feature outside Uber (as it was broken until mid 2021 anyway), but as an FYI, it will cease to be available.

If this behaviour is desirable, an easy workaround is as previously mentioned: Use an activity to launch or signal the workflows in the other domain and block as needed.

PR details
This is a fairly high-risk refactor so it'll take some time to ... (continued)

118 of 134 new or added lines in 9 files covered. (88.06%)

330 existing lines in 30 files now uncovered.

104674 of 146539 relevant lines covered (71.43%)

2619.56 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

79.49
/common/persistence/sql/sqlplugin/mysql/db.go
1
// Copyright (c) 2017 Uber Technologies, Inc.
2
//
3
// Permission is hereby granted, free of charge, to any person obtaining a copy
4
// of this software and associated documentation files (the "Software"), to deal
5
// in the Software without restriction, including without limitation the rights
6
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
// copies of the Software, and to permit persons to whom the Software is
8
// furnished to do so, subject to the following conditions:
9
//
10
// The above copyright notice and this permission notice shall be included in
11
// all copies or substantial portions of the Software.
12
//
13
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
// THE SOFTWARE.
20

21
package mysql
22

23
import (
24
        "context"
25
        "database/sql"
26
        "time"
27

28
        "github.com/VividCortex/mysqlerr"
29
        "github.com/go-sql-driver/mysql"
30
        "github.com/jmoiron/sqlx"
31

32
        "github.com/uber/cadence/common/persistence/sql/sqldriver"
33
        "github.com/uber/cadence/common/persistence/sql/sqlplugin"
34
)
35

36
type (
37
        db struct {
38
                converter   DataConverter
39
                driver      sqldriver.Driver
40
                originalDBs []*sqlx.DB
41
                numDBShards int
42
        }
43
)
44

45
func (mdb *db) GetTotalNumDBShards() int {
32,364✔
46
        return mdb.numDBShards
32,364✔
47
}
32,364✔
48

49
var _ sqlplugin.AdminDB = (*db)(nil)
50
var _ sqlplugin.DB = (*db)(nil)
51
var _ sqlplugin.Tx = (*db)(nil)
52

53
func (mdb *db) IsDupEntryError(err error) bool {
12✔
54
        sqlErr, ok := err.(*mysql.MySQLError)
12✔
55
        // ErrDupEntry MySQL Error 1062 indicates a duplicate primary key i.e. the row already exists,
12✔
56
        // so we don't do the insert and return a ConditionalUpdate error.
12✔
57
        return ok && sqlErr.Number == mysqlerr.ER_DUP_ENTRY
12✔
58
}
12✔
59

60
func (mdb *db) IsNotFoundError(err error) bool {
289✔
61
        return err == sql.ErrNoRows
289✔
62
}
289✔
63

64
func (mdb *db) IsTimeoutError(err error) bool {
78✔
65
        if err == context.DeadlineExceeded {
78✔
66
                return true
×
67
        }
×
68
        sqlErr, ok := err.(*mysql.MySQLError)
78✔
69
        if ok {
156✔
70
                if sqlErr.Number == mysqlerr.ER_NET_READ_INTERRUPTED ||
78✔
71
                        sqlErr.Number == mysqlerr.ER_NET_WRITE_INTERRUPTED ||
78✔
72
                        sqlErr.Number == mysqlerr.ER_LOCK_WAIT_TIMEOUT ||
78✔
73
                        sqlErr.Number == mysqlerr.ER_XA_RBTIMEOUT ||
78✔
74
                        sqlErr.Number == mysqlerr.ER_QUERY_TIMEOUT ||
78✔
75
                        sqlErr.Number == mysqlerr.ER_LOCKING_SERVICE_TIMEOUT ||
78✔
76
                        sqlErr.Number == mysqlerr.ER_REGEXP_TIME_OUT {
78✔
77
                        return true
×
78
                }
×
79
        }
80
        return false
78✔
81
}
82

83
func (mdb *db) IsThrottlingError(err error) bool {
78✔
84
        sqlErr, ok := err.(*mysql.MySQLError)
78✔
85
        if ok {
156✔
86
                if sqlErr.Number == mysqlerr.ER_CON_COUNT_ERROR ||
78✔
87
                        sqlErr.Number == mysqlerr.ER_TOO_MANY_USER_CONNECTIONS ||
78✔
88
                        sqlErr.Number == mysqlerr.ER_TOO_MANY_CONCURRENT_TRXS ||
78✔
89
                        sqlErr.Number == mysqlerr.ER_CLONE_TOO_MANY_CONCURRENT_CLONES {
78✔
90
                        return true
×
91
                }
×
92
        }
93
        return false
78✔
94
}
95

96
// newDB returns an instance of DB, which is a logical
97
// connection to the underlying mysql database
98
// dbShardID is needed when tx is not nil
99
func newDB(xdbs []*sqlx.DB, tx *sqlx.Tx, dbShardID int, numDBShards int) (*db, error) {
6,183✔
100
        driver, err := sqldriver.NewDriver(xdbs, tx, dbShardID)
6,183✔
101
        if err != nil {
6,183✔
102
                return nil, err
×
103
        }
×
104

105
        db := &db{
6,183✔
106
                converter:   &converter{},
6,183✔
107
                originalDBs: xdbs, // this is kept because newDB will be called again when starting a transaction
6,183✔
108
                driver:      driver,
6,183✔
109
                numDBShards: numDBShards,
6,183✔
110
        }
6,183✔
111

6,183✔
112
        return db, nil
6,183✔
113
}
114

115
// BeginTx starts a new transaction and returns a reference to the Tx object
116
func (mdb *db) BeginTx(ctx context.Context, dbShardID int) (sqlplugin.Tx, error) {
6,059✔
117
        xtx, err := mdb.driver.BeginTxx(ctx, dbShardID, nil)
6,059✔
118
        if err != nil {
6,059✔
UNCOV
119
                return nil, err
×
UNCOV
120
        }
×
121
        return newDB(mdb.originalDBs, xtx, dbShardID, mdb.numDBShards)
6,059✔
122
}
123

124
// Commit commits a previously started transaction
125
func (mdb *db) Commit() error {
5,874✔
126
        return mdb.driver.Commit()
5,874✔
127
}
5,874✔
128

129
// Rollback triggers rollback of a previously started transaction
130
func (mdb *db) Rollback() error {
186✔
131
        return mdb.driver.Rollback()
186✔
132
}
186✔
133

134
// Close closes the connection to the mysql db
135
func (mdb *db) Close() error {
125✔
136
        return mdb.driver.Close()
125✔
137
}
125✔
138

139
// PluginName returns the name of the mysql plugin
140
func (mdb *db) PluginName() string {
1,942✔
141
        return PluginName
1,942✔
142
}
1,942✔
143

144
// SupportsTTL returns weather MySQL supports TTL
145
func (mdb *db) SupportsTTL() bool {
3,390✔
146
        return false
3,390✔
147
}
3,390✔
148

149
// MaxAllowedTTL returns the max allowed ttl MySQL supports
150
func (mdb *db) MaxAllowedTTL() (*time.Duration, error) {
×
151
        return nil, sqlplugin.ErrTTLNotSupported
×
152
}
×
153

154
// SupportsTTL returns weather MySQL supports Asynchronous transaction
155
func (mdb *db) SupportsAsyncTransaction() bool {
×
156
        return false
×
157
}
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc