Code Monkey home page Code Monkey logo

moapis / multidb Goto Github PK

View Code? Open in Web Editor NEW
6.0 2.0 0.0 205 KB

Connect your Go app to a group of database Nodes without the need of a SQL aware proxy! Multidb provides a SQL Database multiplexer for parallel queries using Go routines, boosting performance and availabilty.

Home Page: https://godoc.org/github.com/moapis/multidb

License: BSD 3-Clause "New" or "Revised" License

Go 99.84% Shell 0.16%
golang go sql goroutine parallel database bsd-3-clause

multidb's People

Contributors

muhlemmer avatar wolvenspirit avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

multidb's Issues

Error callback function on Node.

In #11, the connErr field was removed. Also, re-connection logic is bound to be removed (#14). By implementing the possibility of adding an error callback function during Node creation, package consumers would be able to monitor and log Node specific errors. As those errors might never get reported during MultiQuery calls, if at least one query on a Node succeeds.

Rewrite examples

In the process of #16: Simplify or remove drivers, the old examples became incorrect and had to be removed.

New examples reflecting the new package interface should be written.

Ignore errors of canceled context

At the moment, if a context is canceled by the caller, we are counting it as a connection error for the node. After enough of such cancels, the node is disregarded.

Package context defines the Canceled variable, against which we can test.

Testing is currently done here:

multidb/node.go

Lines 198 to 211 in 1e5db15

func (n *Node) CheckErr(err error) error {
switch {
case err == nil:
go n.checkFailed(false)
case err == sql.ErrNoRows || err == sql.ErrTxDone:
go n.checkFailed(false)
case n.WhiteList(err):
go n.checkFailed(false)
default:
n.setErr(err)
go n.checkFailed(true)
}
return err
}

This depends on #4, and might be implemented simultanious.

Pretify errors

Some constants are defined like these:

multidb/multidb.go

Lines 34 to 41 in 47558e1

const (
// ErrNoNodes is returned when there are no connected nodes available for the requested operation
ErrNoNodes = "No available nodes"
// ErrNoMaster is returned when no master is available
ErrNoMaster = "No available master, cause: %w"
// ErrSuccesReq is returned when higher than 1.0
ErrSuccesReq = "SuccesReq > 1"
)

The more idiomatic way is to declare global variables, using errors.New(). At the moment the errors are created inside the function scope. This means equality can only be tested based on strings. Instead, this package should offer errors which are easily investigated using errors.Is().

Remove reconnection logic

Reconnection is handled by the SQL driver. Also, if an error is returned on first Connect, it mostly mean an error was made in de dsn, not the actual connection. (SQL library only connects when a Connection needs to be Acquired the first time).

Rewrite error checking

Since Go 1.13, errors can be wrapped. Helper methods are provided to "Unwrap" and test for the originating error. I would like to refactor this package to use the Is method from the errors package, in order to provide more robust testing at:

multidb/node.go

Lines 198 to 211 in 1e5db15

func (n *Node) CheckErr(err error) error {
switch {
case err == nil:
go n.checkFailed(false)
case err == sql.ErrNoRows || err == sql.ErrTxDone:
go n.checkFailed(false)
case n.WhiteList(err):
go n.checkFailed(false)
default:
n.setErr(err)
go n.checkFailed(true)
}
return err
}

Add a utility function for Master error checking

Previously, connections were fully managed by MultiDB. This way it also had full controll over the status of the Master node. However, we are dropping connection management in favor of the standard sql library own (re) connection logic. We have dropped Node specific error statistics in favor of better performance.

This means that, in case the Master starts failing (and another Node has been promoted) this package won't be aware of this. Simply put, if the caller obtains a Master node through MultiDB.Master() or MultiDB.MasterTX(), it should decide itself if a returned error is serious enough to find a new Master.

I would like to add a utility function that can be called in case of errors, that would help with this decision making and optionally even triggering SelectMaster() if needed.

Simplify or remove Drivers

After we drop re-connection logic (#14), it might be feasible to greatly simplify or remove the drivers.Configurator interface. Perhaps make it possible to set DB objects directly. This way we can support all driver implementations without (too much) hassle.

mdb.Add overwrites existing DB with same name

mdb.nodes[name] = db

Overwriting the DB potentially leaves it dangling with open connections in its pool and it will not get garbage collected. In the long run, this can lead to memory leaks, if the caller does not keep track of re-configured databases and proper closing of old entities.

Opening and Closing of DB is not in the scope of this packages. However, we can aide the process by returning the discarded DB from mdb.Add(), so that downstream can choose to close it.

Remove connErr from Node type

multidb/node.go

Lines 71 to 82 in 6696271

type Node struct {
nodeStats
drivers.Configurator
dataSourceName string
// DB holds the raw *sql.DB for direct access.
// Errors produced by calling DB directly are not monitored by this package.
DB *sql.DB
connErr error
reconnectWait time.Duration
reconnecting bool
mtx sync.RWMutex
}

Currently the last encountered error on a DB Node is stored in the connErr field. The last occurred error can be received by the ConnErr function. Recently, Go vet started to complain about reflect.DeepEqual on the error in unit test.

Practically speaking:

  • Setting and getting of the error added complexity to the code and it would be cleaner without
  • If a query cannot complete due to multiple or similar errors, an error is properly returned
  • I don't see a practical point where package consumers will investigate individual Nodes after queries. This would only add in code complexity on the caller's side
  • Queries on a Node are executed concurrently. A mutex is preventing race conditions on the connErr, however it does not guarantee which error is returned from the ConnErr method. A caller might be expecting the error status of the latest called Query, but it may was well return the latest terminated query. There is no way query calls are matched against the connErr state. Meaning this can lead to misunderstanding of the information and bugs.

Set default ReadOnly on non-master TX

multidb/multidb.go

Lines 212 to 218 in e40c963

func (mdb *MultiDB) NodeTx(ctx context.Context, opts *sql.TxOptions) (*Tx, error) {
node, err := mdb.Node()
if err != nil {
return nil, err
}
return node.BeginTx(ctx, opts)
}

When the opts argument is nil, a default &sql.TxOptions{ReadOnly: true} should be set.

Move sqlboiler interface compliance tests to sub-module

github.com/volatiletech/sqlboiler/v4 v4.2.0

Currently the sqlboiler module is pulling lots of dependencies in go.sum. This module is only really used in interface compliance verification like:

multidb/node_test.go

Lines 63 to 65 in 47558e1

// Interface implementation checks
func _() boil.Executor { return &Node{} }
func _() boil.ContextExecutor { return &Node{} }

It would be a "cleaner" impression of the project if we could move this in a sub-module for testing only. Then, we let CI bump the sub-module to the latest commit hash on every push to verify compliance.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.