From 160e58e19efbf978645f2b2c17faba741766c22d Mon Sep 17 00:00:00 2001 From: Antoine Huret Date: Wed, 16 Oct 2024 12:13:08 +0200 Subject: [PATCH] introduce write sync mechanism to prevent concurrency among simultaneous requests (#62) --- README.md | 1 + odoo.go | 39 ++++++++++++++++++++++++++++++--------- 2 files changed, 31 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 754bcde2..3f227e21 100644 --- a/README.md +++ b/README.md @@ -48,6 +48,7 @@ func main() { Password: "admin_password", Database: "database_name", URL: "http://localhost:8069", + SyncWriteRequests: true, // prevent concurrency issues in case of simultaneous write requests }) if err != nil { log.Fatal(err) diff --git a/odoo.go b/odoo.go index 8e9e3a74..0f5168a8 100644 --- a/odoo.go +++ b/odoo.go @@ -7,6 +7,7 @@ import ( "errors" "fmt" "log" + "sync" "github.com/kolo/xmlrpc" ) @@ -21,10 +22,11 @@ var ( // ClientConfig is the configuration to create a new *Client by givin connection infomations. type ClientConfig struct { - Database string - Admin string - Password string - URL string + Database string + Admin string + Password string + URL string + SyncWriteRequests bool } func (c *ClientConfig) valid() bool { @@ -36,11 +38,13 @@ func (c *ClientConfig) valid() bool { // Client provides high and low level functions to interact with odoo type Client struct { - common *xmlrpc.Client - object *xmlrpc.Client - cfg *ClientConfig - uid int64 - auth bool + common *xmlrpc.Client + object *xmlrpc.Client + cfg *ClientConfig + uid int64 + auth bool + syncWriteRequests bool + writeSyncer *sync.Mutex } // NewClient creates a new *Client. @@ -54,6 +58,9 @@ func NewClient(cfg *ClientConfig) (*Client, error) { object: &xmlrpc.Client{}, auth: false, } + if c.cfg.SyncWriteRequests { + c.writeSyncer = &sync.Mutex{} + } if err := c.authenticate(); err != nil { return nil, err } @@ -353,6 +360,11 @@ func (c *Client) ExecuteKw(method, model string, args []interface{}, options *Op if err := c.checkForAuthentication(); err != nil { return nil, err } + if c.cfg.SyncWriteRequests && isWriteMethod(method) { + c.writeSyncer.Lock() + defer c.writeSyncer.Unlock() + } + resp, err := c.objectCall("execute_kw", []interface{}{c.cfg.Database, c.uid, c.cfg.Password, model, method, args, options}) if err != nil { return nil, err @@ -449,3 +461,12 @@ func argsFromCriteria(c *Criteria) []interface{} { } return []interface{}{} } + +func isWriteMethod(method string) bool { + switch method { + case "create", "write", "unlink": + return true + default: + return false + } +}