From 06c49179f8b210f739e95e3c77b084d5e4c8fc59 Mon Sep 17 00:00:00 2001 From: "i.navrotskyj" Date: Wed, 3 Jul 2024 14:31:24 +0300 Subject: [PATCH] DEV-4252 --- go.mod | 206 --------------------------------- queue/call_predict.go | 8 +- queue/team.go | 44 +++++-- store/sqlstore/member_store.go | 49 +++++--- store/store.go | 1 + 5 files changed, 73 insertions(+), 235 deletions(-) diff --git a/go.mod b/go.mod index 9160d3a9..ce3e416a 100644 --- a/go.mod +++ b/go.mod @@ -23,251 +23,45 @@ require ( ) require ( - 4d63.com/gocheckcompilerdirectives v1.2.1 // indirect - 4d63.com/gochecknoglobals v0.2.1 // indirect buf.build/gen/go/grpc-ecosystem/grpc-gateway/protocolbuffers/go v1.34.2-20231027202514-3f42134f4c56.2 // indirect buf.build/gen/go/webitel/chat/grpc/go v1.4.0-20240702143950-364c79a4f8d2.2 // indirect buf.build/gen/go/webitel/chat/protocolbuffers/go v1.34.2-20240702143950-364c79a4f8d2.2 // indirect - buf.build/gen/go/webitel/engine/grpc/go v1.4.0-20240618123100-3e740393d1cc.1 // indirect buf.build/gen/go/webitel/engine/protocolbuffers/go v1.34.2-20240627112700-3fe53516f45c.2 // indirect - buf.build/gen/go/webitel/logger/grpc/go v1.3.0-20240404135439-f6c7830c29dd.2 // indirect - buf.build/gen/go/webitel/logger/protocolbuffers/go v1.33.0-20240404135439-f6c7830c29dd.1 // indirect buf.build/gen/go/webitel/webitel-go/grpc/go v1.3.0-20240527133231-c12eb2a85c36.3 // indirect buf.build/gen/go/webitel/webitel-go/protocolbuffers/go v1.34.1-20240527133231-c12eb2a85c36.1 // indirect buf.build/gen/go/webitel/workflow/grpc/go v1.3.0-20240411120545-24ef43af6db3.2 // indirect - cloud.google.com/go v0.112.0 // indirect - cloud.google.com/go/compute v1.23.3 // indirect - cloud.google.com/go/compute/metadata v0.2.3 // indirect - cloud.google.com/go/firestore v1.14.0 // indirect - cloud.google.com/go/iam v1.1.5 // indirect - cloud.google.com/go/longrunning v0.5.4 // indirect - cloud.google.com/go/storage v1.36.0 // indirect - firebase.google.com/go v3.13.0+incompatible // indirect - github.com/Abirdcfly/dupword v0.0.11 // indirect - github.com/Antonboom/errname v0.1.9 // indirect - github.com/Antonboom/nilnil v0.1.3 // indirect - github.com/BoRuDar/configuration/v4 v4.2.2 // indirect - github.com/BurntSushi/toml v1.2.1 // indirect - github.com/Djarvur/go-err113 v0.0.0-20210108212216-aea10b59be24 // indirect - github.com/GaijinEntertainment/go-exhaustruct/v2 v2.3.0 // indirect - github.com/Masterminds/semver v1.5.0 // indirect - github.com/Masterminds/squirrel v1.5.4 // indirect - github.com/OpenPeeDeeP/depguard v1.1.1 // indirect - github.com/alexkohler/prealloc v1.0.0 // indirect - github.com/alingse/asasalint v0.0.11 // indirect - github.com/andres-erbsen/clock v0.0.0-20160526145045-9e14626cd129 // indirect github.com/armon/go-metrics v0.4.1 // indirect - github.com/ashanbrown/forbidigo v1.5.1 // indirect - github.com/ashanbrown/makezero v1.1.1 // indirect - github.com/beorn7/perks v1.0.1 // indirect - github.com/bkielbasa/cyclop v1.2.0 // indirect - github.com/blizzy78/varnamelen v0.8.0 // indirect - github.com/bombsimon/wsl/v3 v3.4.0 // indirect - github.com/breml/bidichk v0.2.4 // indirect - github.com/breml/errchkjson v0.3.1 // indirect - github.com/butuzov/ireturn v0.1.1 // indirect - github.com/cespare/xxhash/v2 v2.2.0 // indirect - github.com/charithe/durationcheck v0.0.10 // indirect - github.com/chavacava/garif v0.0.0-20230227094218-b8c73b2037b8 // indirect - github.com/curioswitch/go-reassign v0.2.0 // indirect - github.com/daixiang0/gci v0.10.1 // indirect - github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect - github.com/denis-tingaikin/go-header v0.4.3 // indirect - github.com/discoviking/fsm v0.0.0-20150126104936-f4a273feecca // indirect - github.com/esimonov/ifshort v1.0.4 // indirect - github.com/ettle/strcase v0.1.1 // indirect github.com/fatih/color v1.15.0 // indirect - github.com/fatih/structtag v1.2.0 // indirect - github.com/felixge/httpsnoop v1.0.4 // indirect - github.com/firefart/nonamedreturns v1.0.4 // indirect - github.com/fsnotify/fsnotify v1.5.4 // indirect - github.com/fzipp/gocyclo v0.6.0 // indirect - github.com/ghettovoice/gosip v0.0.0-20231005134608-3b981d26e5cc // indirect - github.com/go-critic/go-critic v0.7.0 // indirect - github.com/go-logr/logr v1.3.0 // indirect - github.com/go-logr/stdr v1.2.2 // indirect - github.com/go-playground/form v3.1.4+incompatible // indirect - github.com/go-toolsmith/astcast v1.1.0 // indirect - github.com/go-toolsmith/astcopy v1.1.0 // indirect - github.com/go-toolsmith/astequal v1.1.0 // indirect - github.com/go-toolsmith/astfmt v1.1.0 // indirect - github.com/go-toolsmith/astp v1.1.0 // indirect - github.com/go-toolsmith/strparse v1.1.0 // indirect - github.com/go-toolsmith/typep v1.1.0 // indirect - github.com/go-xmlfmt/xmlfmt v1.1.2 // indirect - github.com/gobwas/glob v0.2.3 // indirect - github.com/gobwas/httphead v0.1.0 // indirect - github.com/gobwas/pool v0.2.1 // indirect - github.com/gobwas/ws v1.1.0-rc.1 // indirect - github.com/gofrs/flock v0.8.1 // indirect - github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.3 // indirect - github.com/golangci/check v0.0.0-20180506172741-cfe4005ccda2 // indirect - github.com/golangci/dupl v0.0.0-20180902072040-3e9179ac440a // indirect - github.com/golangci/go-misc v0.0.0-20220329215616-d24fe342adfe // indirect - github.com/golangci/gofmt v0.0.0-20220901101216-f2edd75033f2 // indirect - github.com/golangci/golangci-lint v1.52.2 // indirect - github.com/golangci/lint-1 v0.0.0-20191013205115-297bf364a8e0 // indirect - github.com/golangci/maligned v0.0.0-20180506175553-b1d89398deca // indirect - github.com/golangci/misspell v0.4.0 // indirect - github.com/golangci/revgrep v0.0.0-20220804021717-745bb2f7c2e6 // indirect - github.com/golangci/unconvert v0.0.0-20180507085042-28b1c447d1f4 // indirect - github.com/google/go-cmp v0.6.0 // indirect - github.com/google/s2a-go v0.1.7 // indirect github.com/google/uuid v1.6.0 // indirect - github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect - github.com/googleapis/gax-go/v2 v2.12.0 // indirect - github.com/gordonklaus/ineffassign v0.0.0-20230107090616-13ace0543b28 // indirect - github.com/gorilla/handlers v1.5.1 // indirect - github.com/gorilla/mux v1.8.0 // indirect - github.com/gorilla/websocket v1.5.0 // indirect - github.com/gostaticanalysis/analysisutil v0.7.1 // indirect - github.com/gostaticanalysis/comment v1.4.2 // indirect - github.com/gostaticanalysis/forcetypeassert v0.1.0 // indirect - github.com/gostaticanalysis/nilerr v0.1.1 // indirect github.com/hashicorp/consul/api v1.25.1 // indirect - github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-hclog v1.5.0 // indirect github.com/hashicorp/go-immutable-radix v1.3.1 // indirect - github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/hashicorp/go-rootcerts v1.0.2 // indirect - github.com/hashicorp/go-version v1.6.0 // indirect github.com/hashicorp/golang-lru v1.0.2 // indirect - github.com/hashicorp/hcl v1.0.0 // indirect github.com/hashicorp/serf v0.10.1 // indirect - github.com/hexops/gotextdiff v1.0.3 // indirect - github.com/inconshreveable/mousetrap v1.0.1 // indirect - github.com/jgautheron/goconst v1.5.1 // indirect - github.com/jingyugao/rowserrcheck v1.1.1 // indirect - github.com/jirfag/go-printf-func-name v0.0.0-20200119135958-7558a9eaa5af // indirect - github.com/jmoiron/sqlx v1.3.5 // indirect - github.com/jpillora/backoff v1.0.0 // indirect - github.com/julz/importas v0.1.0 // indirect - github.com/junk1tm/musttag v0.5.0 // indirect - github.com/kisielk/errcheck v1.6.3 // indirect - github.com/kisielk/gotool v1.0.0 // indirect - github.com/kkHAIKE/contextcheck v1.1.4 // indirect github.com/kr/pretty v0.3.1 // indirect - github.com/kulti/thelper v0.6.3 // indirect - github.com/kunwardeep/paralleltest v1.0.6 // indirect - github.com/kyoh86/exportloopref v0.1.11 // indirect - github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 // indirect - github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 // indirect - github.com/ldez/gomoddirectives v0.2.3 // indirect - github.com/ldez/tagliatelle v0.4.0 // indirect - github.com/leonklingele/grouper v1.1.1 // indirect - github.com/lufeee/execinquery v1.2.1 // indirect - github.com/magiconair/properties v1.8.7 // indirect - github.com/maratori/testableexamples v1.0.0 // indirect - github.com/maratori/testpackage v1.1.1 // indirect - github.com/matoous/godox v0.0.0-20230222163458-006bad1f9d26 // indirect - github.com/matryer/moq v0.3.1 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.19 // indirect - github.com/mattn/go-runewidth v0.0.9 // indirect - github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect - github.com/mbilski/exhaustivestruct v1.2.0 // indirect - github.com/mbobakov/grpc-consul-resolver v1.5.2 // indirect - github.com/mgechev/revive v1.3.1 // indirect - github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect - github.com/moricho/tparallel v0.3.1 // indirect - github.com/nakabonne/nestif v0.3.1 // indirect - github.com/nbutton23/zxcvbn-go v0.0.0-20210217022336-fa2cb2858354 // indirect github.com/nicksnyder/go-i18n v1.10.1 // indirect - github.com/nishanths/exhaustive v0.9.5 // indirect - github.com/nishanths/predeclared v0.2.2 // indirect - github.com/nunnatsa/ginkgolinter v0.9.0 // indirect - github.com/olekukonko/tablewriter v0.0.5 // indirect github.com/pelletier/go-toml v1.9.5 // indirect - github.com/pelletier/go-toml/v2 v2.0.5 // indirect - github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect - github.com/polyfloyd/go-errorlint v1.4.0 // indirect - github.com/prometheus/client_golang v1.12.1 // indirect - github.com/prometheus/client_model v0.4.0 // indirect - github.com/prometheus/common v0.32.1 // indirect - github.com/prometheus/procfs v0.7.3 // indirect - github.com/quasilyte/go-ruleguard v0.3.19 // indirect - github.com/quasilyte/gogrep v0.5.0 // indirect - github.com/quasilyte/regex/syntax v0.0.0-20210819130434-b3f0c404a727 // indirect - github.com/quasilyte/stdinfo v0.0.0-20220114132959-f7386bf02567 // indirect github.com/rogpeppe/go-internal v1.11.0 // indirect - github.com/ryancurrah/gomodguard v1.3.0 // indirect - github.com/ryanrolds/sqlclosecheck v0.4.0 // indirect - github.com/sanposhiho/wastedassign/v2 v2.0.7 // indirect - github.com/sashamelentyev/interfacebloat v1.1.0 // indirect - github.com/sashamelentyev/usestdlibvars v1.23.0 // indirect - github.com/satori/go.uuid v1.2.1-0.20181028125025-b2ce2384e17b // indirect - github.com/securego/gosec/v2 v2.15.0 // indirect - github.com/shazow/go-diff v0.0.0-20160112020656-b6b7b6733b8c // indirect - github.com/sirupsen/logrus v1.9.0 // indirect - github.com/sivchari/containedctx v1.0.2 // indirect - github.com/sivchari/nosnakecase v1.7.0 // indirect - github.com/sivchari/tenv v1.7.1 // indirect - github.com/sonatard/noctx v0.0.2 // indirect - github.com/sourcegraph/go-diff v0.7.0 // indirect - github.com/spf13/afero v1.9.2 // indirect - github.com/spf13/cast v1.5.0 // indirect - github.com/spf13/cobra v1.6.1 // indirect - github.com/spf13/jwalterweatherman v1.1.0 // indirect - github.com/spf13/pflag v1.0.5 // indirect - github.com/spf13/viper v1.12.0 // indirect - github.com/ssgreg/nlreturn/v2 v2.2.1 // indirect - github.com/stbenjam/no-sprintf-host-port v0.1.1 // indirect - github.com/stretchr/objx v0.5.0 // indirect - github.com/stretchr/testify v1.8.4 // indirect - github.com/subosito/gotenv v1.4.1 // indirect - github.com/t-yuki/gocover-cobertura v0.0.0-20180217150009-aaee18c8195c // indirect - github.com/tdakkota/asciicheck v0.2.0 // indirect - github.com/tetafro/godot v1.4.11 // indirect - github.com/tevino/abool v1.2.0 // indirect - github.com/timakin/bodyclose v0.0.0-20221125081123-e39cf3fc478e // indirect - github.com/timonwong/loggercheck v0.9.4 // indirect - github.com/tomarrell/wrapcheck/v2 v2.8.1 // indirect - github.com/tommy-muehle/go-mnd/v2 v2.5.1 // indirect - github.com/ultraware/funlen v0.0.3 // indirect - github.com/ultraware/whitespace v0.0.5 // indirect - github.com/uudashr/gocognit v1.0.6 // indirect - github.com/x-cray/logrus-prefixed-formatter v0.5.2 // indirect - github.com/yagipy/maintidx v1.0.0 // indirect - github.com/yeya24/promlinter v0.2.0 // indirect - gitlab.com/bosi/decorder v0.2.3 // indirect - go.opencensus.io v0.24.0 // indirect - go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1 // indirect - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1 // indirect - go.opentelemetry.io/otel v1.21.0 // indirect - go.opentelemetry.io/otel/metric v1.21.0 // indirect - go.opentelemetry.io/otel/trace v1.21.0 // indirect go.uber.org/atomic v1.11.0 // indirect go.uber.org/multierr v1.11.0 // indirect - go.uber.org/ratelimit v0.2.0 // indirect go.uber.org/zap v1.26.0 // indirect - golang.org/x/crypto v0.18.0 // indirect golang.org/x/exp v0.0.0-20231006140011-7918f672742d // indirect - golang.org/x/exp/typeparams v0.0.0-20230224173230-c95f2b4c22f2 // indirect - golang.org/x/mod v0.13.0 // indirect golang.org/x/net v0.20.0 // indirect golang.org/x/oauth2 v0.16.0 // indirect golang.org/x/sys v0.16.0 // indirect - golang.org/x/term v0.16.0 // indirect golang.org/x/text v0.14.0 // indirect - golang.org/x/tools v0.14.0 // indirect - google.golang.org/api v0.155.0 // indirect google.golang.org/appengine v1.6.8 // indirect google.golang.org/genproto v0.0.0-20240123012728-ef4313101c80 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20240123012728-ef4313101c80 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240123012728-ef4313101c80 // indirect google.golang.org/protobuf v1.34.2 // indirect - gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect - gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect - honnef.co/go/tools v0.4.3 // indirect - mvdan.cc/gofumpt v0.4.0 // indirect - mvdan.cc/interfacer v0.0.0-20180901003855-c20040233aed // indirect - mvdan.cc/lint v0.0.0-20170908181259-adc824a0674b // indirect - mvdan.cc/unparam v0.0.0-20221223090309-7455f1af531d // indirect ) diff --git a/queue/call_predict.go b/queue/call_predict.go index 8fe6252c..8852e080 100644 --- a/queue/call_predict.go +++ b/queue/call_predict.go @@ -460,7 +460,13 @@ func (queue *PredictCallQueue) runOfferingAgents(attempt *Attempt, mCall call_ma } if agentCall.BridgeAt() == 0 { - team.MissedAgentAndWaitingAttempt(attempt, agent) + agentCause := agentCall.HangupCause() + if agentCause == model.CALL_HANGUP_ORIGINATOR_CANCEL || agentCause == model.CALL_HANGUP_LOSE_RACE { + team.WaitingAgentAndWaitingAttempt(attempt, agent) + } else { + team.MissedAgentAndWaitingAttempt(attempt, agent) + } + attempt.SetState(model.MemberStateWaitAgent) if agentCall != nil && agentCall.HangupAt() == 0 { //TODO WaitForHangup diff --git a/queue/team.go b/queue/team.go index 13552c36..2861fa35 100644 --- a/queue/team.go +++ b/queue/team.go @@ -66,11 +66,11 @@ func (at *agentTeam) CallTimeout() uint16 { return at.data.CallTimeout } -func (at agentTeam) InviteChatTimeout() uint16 { +func (at *agentTeam) InviteChatTimeout() uint16 { return at.data.InviteChatTimeout } -func (at agentTeam) TaskAcceptTimeout() uint16 { +func (at *agentTeam) TaskAcceptTimeout() uint16 { return at.data.TaskAcceptTimeout } @@ -164,7 +164,7 @@ func (tm *agentTeam) Answered(attempt *Attempt, agent agent_manager.AgentObject) e := NewAnsweredEvent(attempt, agent.UserId(), timestamp) err := tm.teamManager.mq.AgentChannelEvent(attempt.channel, attempt.domainId, attempt.QueueId(), agent.UserId(), e) if err != nil { - wlog.Error(err.Error()) + attempt.Log(err.Error()) return } } @@ -177,7 +177,7 @@ func (tm *agentTeam) Bridged(attempt *Attempt, agent agent_manager.AgentObject) timestamp, err := tm.teamManager.store.Member().SetAttemptBridged(attempt.Id()) if err != nil { - wlog.Error(err.Error()) + attempt.Log(err.Error()) return } attempt.SetState(model.MemberStateBridged) @@ -185,7 +185,7 @@ func (tm *agentTeam) Bridged(attempt *Attempt, agent agent_manager.AgentObject) e := NewBridgedEventEvent(attempt, agent.UserId(), timestamp) err = tm.teamManager.mq.AgentChannelEvent(attempt.channel, attempt.domainId, attempt.QueueId(), agent.UserId(), e) if err != nil { - wlog.Error(err.Error()) + attempt.Log(err.Error()) return } } @@ -224,7 +224,7 @@ func (tm *agentTeam) SetWrap(queue QueueObject, attempt *Attempt, agent agent_ma wlog.Error(err.Error()) } } else { - wlog.Error(err.Error()) + attempt.Log(err.Error()) } queue.Leaving(attempt) } @@ -284,7 +284,7 @@ func (tm *agentTeam) Reporting(queue QueueObject, attempt *Attempt, agent agent_ e := NewProcessingEventEvent(attempt, agent.UserId(), timestamp, timeoutSec, queue.ProcessingRenewalSec()) err = tm.teamManager.mq.AgentChannelEvent(attempt.channel, attempt.domainId, attempt.QueueId(), agent.UserId(), e) if err != nil { - wlog.Error(err.Error()) + attempt.Log(err.Error()) return } @@ -300,7 +300,7 @@ func (tm *agentTeam) Missed(attempt *Attempt, agent agent_manager.AgentObject) { missed, err := tm.teamManager.store.Member().SetAttemptMissed(attempt.Id(), int(tm.NoAnswerDelayTime()), attempt.maxAttempts, attempt.waitBetween, attempt.perNumbers) if err != nil { - wlog.Error(err.Error()) + attempt.Log(err.Error()) return } @@ -320,7 +320,7 @@ func (tm *agentTeam) CancelAgentAttempt(attempt *Attempt, agent agent_manager.Ag missed, err := tm.teamManager.store.Member().CancelAgentAttempt(attempt.Id(), int(tm.NoAnswerDelayTime())) if err != nil { - wlog.Error(err.Error()) + attempt.Log(err.Error()) return } @@ -337,7 +337,7 @@ func (tm *agentTeam) MissedAgent(missed *model.MissedAgent, attempt *Attempt, ag e := NewMissedEventEvent(attempt, agent.UserId(), missed.Timestamp, missed.Timestamp+(int64(tm.NoAnswerDelayTime())*1000)) err := tm.teamManager.mq.AgentChannelEvent(attempt.channel, attempt.domainId, attempt.QueueId(), agent.UserId(), e) if err != nil { - wlog.Error(err.Error()) + attempt.Log(err.Error()) return } } @@ -345,7 +345,7 @@ func (tm *agentTeam) MissedAgent(missed *model.MissedAgent, attempt *Attempt, ag func (tm *agentTeam) MissedAgentAndWaitingAttempt(attempt *Attempt, agent agent_manager.AgentObject) { missed, err := tm.teamManager.store.Member().SetAttemptMissedAgent(attempt.Id(), int(tm.NoAnswerDelayTime())) if err != nil { - wlog.Error(err.Error()) + attempt.Log(err.Error()) return } @@ -354,6 +354,25 @@ func (tm *agentTeam) MissedAgentAndWaitingAttempt(attempt *Attempt, agent agent_ attempt.agentChannel = nil } +func (tm *agentTeam) WaitingAgentAndWaitingAttempt(attempt *Attempt, agent agent_manager.AgentObject) { + err := tm.teamManager.store.Member().SetAttemptWaitingAgent(attempt.Id(), int(tm.NoAnswerDelayTime())) + if err != nil { + attempt.Log(err.Error()) + return + } + + e := NewWaitingChannelEvent(attempt.channel, agent.UserId(), model.NewInt64(attempt.Id()), model.GetMillis()) + err = tm.teamManager.mq.AgentChannelEvent(attempt.channel, agent.DomainId(), attempt.QueueId(), agent.UserId(), e) + + attempt.agent = nil + attempt.agentChannel = nil + + if err != nil { + attempt.Log(err.Error()) + return + } +} + func (tm *agentTeam) SetAgentMaxNoAnswer(agent agent_manager.AgentObject) { if err := tm.teamManager.app.SetAgentBreakOut(agent); err != nil { wlog.Error(fmt.Sprintf("agent \"%s\" change to [break_out] error %s", agent.Name(), err.Error())) @@ -369,7 +388,8 @@ func (tm *agentTeam) Transfer(attempt *Attempt, agent agent_manager.AgentObject) e := NewWrapTimeEventEvent(attempt.channel, model.NewInt64(attempt.Id()), agent.UserId(), timestamp, timestamp+(int64(tm.WrapUpTime()*1000))) err := tm.teamManager.mq.AgentChannelEvent(attempt.channel, attempt.domainId, attempt.QueueId(), agent.UserId(), e) if err != nil { - wlog.Error(err.Error()) + attempt.Log(err.Error()) + return } return diff --git a/store/sqlstore/member_store.go b/store/sqlstore/member_store.go index f8ab70dd..816ffa36 100644 --- a/store/sqlstore/member_store.go +++ b/store/sqlstore/member_store.go @@ -24,7 +24,7 @@ func (s *SqlMemberStore) CreateTableIfNotExists() { } -func (s SqlMemberStore) ReserveMembersByNode(nodeId string, enableOmnichannel bool) (int64, *model.AppError) { +func (s *SqlMemberStore) ReserveMembersByNode(nodeId string, enableOmnichannel bool) (int64, *model.AppError) { if i, err := s.GetMaster().SelectNullInt(`call call_center.cc_distribute(:DisableOmnichannel::bool)`, map[string]interface{}{ "DisableOmnichannel": !enableOmnichannel, }); err != nil { @@ -36,7 +36,7 @@ func (s SqlMemberStore) ReserveMembersByNode(nodeId string, enableOmnichannel bo } } -func (s SqlMemberStore) UnReserveMembersByNode(nodeId, cause string) (int64, *model.AppError) { +func (s *SqlMemberStore) UnReserveMembersByNode(nodeId, cause string) (int64, *model.AppError) { if i, err := s.GetMaster().SelectInt(`select s as count from call_center.cc_un_reserve_members_with_resources($1, $2) s`, nodeId, cause); err != nil { return 0, model.NewAppError("SqlMemberStore.UnReserveMembers", "store.sql_member.un_reserve_member_resources.app_error", @@ -46,7 +46,7 @@ func (s SqlMemberStore) UnReserveMembersByNode(nodeId, cause string) (int64, *mo } } -func (s SqlMemberStore) GetActiveMembersAttempt(nodeId string) ([]*model.MemberAttempt, *model.AppError) { +func (s *SqlMemberStore) GetActiveMembersAttempt(nodeId string) ([]*model.MemberAttempt, *model.AppError) { var members []*model.MemberAttempt if _, err := s.GetMaster().Select(&members, `select * from call_center.cc_set_active_members($1) s`, nodeId); err != nil { @@ -58,7 +58,7 @@ func (s SqlMemberStore) GetActiveMembersAttempt(nodeId string) ([]*model.MemberA } } -func (s SqlMemberStore) SetAttemptState(id int64, state int) *model.AppError { +func (s *SqlMemberStore) SetAttemptState(id int64, state int) *model.AppError { if _, err := s.GetMaster().Exec(`update call_center.cc_member_attempt set state = :State where id = :Id`, map[string]interface{}{"Id": id, "State": state}); err != nil { @@ -69,7 +69,7 @@ func (s SqlMemberStore) SetAttemptState(id int64, state int) *model.AppError { return nil } -func (s SqlMemberStore) SetAttemptFindAgent(id int64) *model.AppError { +func (s *SqlMemberStore) SetAttemptFindAgent(id int64) *model.AppError { if _, err := s.GetMaster().Exec(`update call_center.cc_member_attempt set state = :State, agent_id = null, @@ -86,7 +86,7 @@ func (s SqlMemberStore) SetAttemptFindAgent(id int64) *model.AppError { return nil } -func (s SqlMemberStore) AnswerPredictAndFindAgent(id int64) *model.AppError { +func (s *SqlMemberStore) AnswerPredictAndFindAgent(id int64) *model.AppError { if _, err := s.GetMaster().Exec(`update call_center.cc_member_attempt set state = :State, agent_id = null, @@ -103,7 +103,7 @@ func (s SqlMemberStore) AnswerPredictAndFindAgent(id int64) *model.AppError { return nil } -func (s SqlMemberStore) SetDistributeCancel(id int64, description string, nextDistributeSec uint32, stop bool, vars map[string]string) *model.AppError { +func (s *SqlMemberStore) SetDistributeCancel(id int64, description string, nextDistributeSec uint32, stop bool, vars map[string]string) *model.AppError { _, err := s.GetMaster().Exec(`call call_center.cc_attempt_distribute_cancel(:Id::int8, :Desc::varchar, :NextSec::int4, :Stop::bool, :Vars::jsonb)`, map[string]interface{}{ "Id": id, @@ -121,7 +121,7 @@ func (s SqlMemberStore) SetDistributeCancel(id int64, description string, nextDi return nil } -func (s SqlMemberStore) DistributeCallToQueue(node string, queueId int64, callId string, vars map[string]string, bucketId *int32, priority int, stickyAgentId *int) (*model.InboundCallQueue, *model.AppError) { +func (s *SqlMemberStore) DistributeCallToQueue(node string, queueId int64, callId string, vars map[string]string, bucketId *int32, priority int, stickyAgentId *int) (*model.InboundCallQueue, *model.AppError) { var att *model.InboundCallQueue err := s.GetMaster().SelectOne(&att, `select * from call_center.cc_distribute_inbound_call_to_queue(:AppId::varchar, :QueueId::int8, :CallId::varchar, :Variables::jsonb, @@ -172,7 +172,7 @@ as x ( return att, nil } -func (s SqlMemberStore) DistributeCallToAgent(node string, callId string, vars map[string]string, agentId int32, force bool, params *model.QueueDumpParams) (*model.InboundCallAgent, *model.AppError) { +func (s *SqlMemberStore) DistributeCallToAgent(node string, callId string, vars map[string]string, agentId int32, force bool, params *model.QueueDumpParams) (*model.InboundCallAgent, *model.AppError) { var att *model.InboundCallAgent err := s.GetMaster().SelectOne(&att, `select * @@ -215,7 +215,7 @@ where :Force::bool or not exists(select 1 from call_center.cc_member_attempt a w return att, nil } -func (s SqlMemberStore) DistributeTaskToAgent(node string, domainId int64, agentId int32, dest []byte, vars map[string]string, force bool, params *model.QueueDumpParams) (*model.TaskToAgent, *model.AppError) { +func (s *SqlMemberStore) DistributeTaskToAgent(node string, domainId int64, agentId int32, dest []byte, vars map[string]string, force bool, params *model.QueueDumpParams) (*model.TaskToAgent, *model.AppError) { var att *model.TaskToAgent err := s.GetMaster().SelectOne(&att, `select * @@ -246,7 +246,7 @@ where :Force::bool or not exists(select 1 from call_center.cc_member_attempt a w return att, nil } -func (s SqlMemberStore) DistributeCallToQueueCancel(id int64) *model.AppError { +func (s *SqlMemberStore) DistributeCallToQueueCancel(id int64) *model.AppError { _, err := s.GetMaster().Exec(`update call_center.cc_member_attempt set result = 'cancel', state = 'leaving', @@ -264,7 +264,7 @@ where id = :Id`, map[string]interface{}{ return nil } -func (s SqlMemberStore) DistributeChatToQueue(node string, queueId int64, convId string, vars map[string]string, bucketId *int32, priority int, stickyAgentId *int) (*model.InboundChatQueue, *model.AppError) { +func (s *SqlMemberStore) DistributeChatToQueue(node string, queueId int64, convId string, vars map[string]string, bucketId *int32, priority int, stickyAgentId *int) (*model.InboundChatQueue, *model.AppError) { var attempt *model.InboundChatQueue var v *string @@ -313,7 +313,7 @@ as x ( return attempt, nil } -func (s SqlMemberStore) DistributeDirect(node string, memberId int64, communicationId, agentId int) (*model.MemberAttempt, *model.AppError) { +func (s *SqlMemberStore) DistributeDirect(node string, memberId int64, communicationId, agentId int) (*model.MemberAttempt, *model.AppError) { var res *model.MemberAttempt err := s.GetMaster().SelectOne(&res, `select * from call_center.cc_distribute_direct_member_to_queue(:AppId, :MemberId, :CommunicationId, :AgentId)`, map[string]interface{}{ @@ -442,6 +442,23 @@ where x.last_state_change notnull `, map[string]interface{}{ return res, nil } +func (s *SqlMemberStore) SetAttemptWaitingAgent(attemptId int64, agentHoldSec int) *model.AppError { + _, err := s.GetMaster().SelectNullInt(`select 1 as ok +from call_center.cc_attempt_waiting_agent(:AttemptId, :AgentHoldSec) + as x (last_state_change timestamptz, no_answers int) +where x.last_state_change notnull `, map[string]interface{}{ + "AttemptId": attemptId, + "AgentHoldSec": agentHoldSec, + }) + + if err != nil { + return model.NewAppError("SqlMemberStore.SetAttemptWaitingAgent", "store.sql_member.set_attempt_waiting_agent.app_error", nil, + fmt.Sprintf("AttemptId=%v %s", attemptId, err.Error()), http.StatusInternalServerError) + } + + return nil +} + func (s *SqlMemberStore) SetAttemptReporting(attemptId int64, deadlineSec uint32) (int64, *model.AppError) { timestamp, err := s.GetMaster().SelectInt(`with att as ( update call_center.cc_member_attempt @@ -725,7 +742,7 @@ where x.last_state_change notnull`, map[string]interface{}{ return result, nil } -func (s SqlMemberStore) SaveToHistory() ([]*model.HistoryAttempt, *model.AppError) { +func (s *SqlMemberStore) SaveToHistory() ([]*model.HistoryAttempt, *model.AppError) { var res []*model.HistoryAttempt _, err := s.GetMaster().Select(&res, `with del as materialized ( @@ -765,7 +782,7 @@ returning id, result`) return res, nil } -func (s SqlMemberStore) CreateConversationChannel(parentChannelId, name string, attemptId int64) (string, *model.AppError) { +func (s *SqlMemberStore) CreateConversationChannel(parentChannelId, name string, attemptId int64) (string, *model.AppError) { res, err := s.GetMaster().SelectStr(`insert into call_center.cc_msg_participants (name, conversation_id, attempt_id) select :Name, parent.conversation_id, :AttemptId from call_center.cc_msg_participants parent @@ -786,7 +803,7 @@ returning channel_id`, map[string]interface{}{ } -func (s SqlMemberStore) RefreshQueueStatsLast2H() *model.AppError { +func (s *SqlMemberStore) RefreshQueueStatsLast2H() *model.AppError { _, err := s.GetMaster().Exec(`refresh materialized view CONCURRENTLY call_center.cc_distribute_stats`) if err != nil { diff --git a/store/store.go b/store/store.go index 8012d88a..db5e927a 100644 --- a/store/store.go +++ b/store/store.go @@ -71,6 +71,7 @@ type MemberStore interface { SetAttemptAbandonedWithParams(attemptId int64, maxAttempts uint, sleep uint64, vars map[string]string, perNum bool, excludeNum bool, redial bool, desc *string, stickyAgentId *int32) (*model.AttemptLeaving, *model.AppError) + SetAttemptWaitingAgent(attemptId int64, agentHoldSec int) *model.AppError SetAttemptMissedAgent(attemptId int64, agentHoldSec int) (*model.MissedAgent, *model.AppError) SetAttemptMissed(id int64, agentHoldTime int, maxAttempts uint, waitBetween uint64, perNum bool) (*model.MissedAgent, *model.AppError) SetAttemptResult(id int64, result string, channelState string, agentHoldTime int, vars map[string]string,