projects
/
arvados.git
/ blobdiff
summary
|
shortlog
|
log
|
commit
|
commitdiff
|
tree
raw
|
inline
| side by side
12087: Exit "wait for low water mark" loop if session terminates.
[arvados.git]
/
services
/
ws
/
event_source.go
diff --git
a/services/ws/event_source.go
b/services/ws/event_source.go
index ed1ac0db97a29f8bd3c9e53791e00e2eda6565dd..cfb828b2a5d84c6d16407866374e1f4900185f84 100644
(file)
--- a/
services/ws/event_source.go
+++ b/
services/ws/event_source.go
@@
-1,3
+1,7
@@
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
package main
import (
package main
import (
@@
-29,8
+33,9
@@
func (c pgConfig) ConnectionString() string {
}
type pgEventSource struct {
}
type pgEventSource struct {
- DataSource string
- QueueSize int
+ DataSource string
+ MaxOpenConns int
+ QueueSize int
db *sql.DB
pqListener *pq.Listener
db *sql.DB
pqListener *pq.Listener
@@
-70,9
+75,14
@@
func (ps *pgEventSource) setup() {
ps.ready = make(chan bool)
}
ps.ready = make(chan bool)
}
-// waitReady returns when private fields (cancel, db) are available
-// for tests to use.
-func (ps *pgEventSource) waitReady() {
+// Close stops listening for new events and disconnects all clients.
+func (ps *pgEventSource) Close() {
+ ps.WaitReady()
+ ps.cancel()
+}
+
+// WaitReady returns when the event listener is connected.
+func (ps *pgEventSource) WaitReady() {
ps.setupOnce.Do(ps.setup)
<-ps.ready
}
ps.setupOnce.Do(ps.setup)
<-ps.ready
}
@@
-84,6
+94,12
@@
func (ps *pgEventSource) Run() {
defer logger(nil).Debug("pgEventSource Run finished")
ps.setupOnce.Do(ps.setup)
defer logger(nil).Debug("pgEventSource Run finished")
ps.setupOnce.Do(ps.setup)
+ ready := ps.ready
+ defer func() {
+ if ready != nil {
+ close(ready)
+ }
+ }()
ctx, cancel := context.WithCancel(context.Background())
ps.cancel = cancel
ctx, cancel := context.WithCancel(context.Background())
ps.cancel = cancel
@@
-101,11
+117,15
@@
func (ps *pgEventSource) Run() {
db, err := sql.Open("postgres", ps.DataSource)
if err != nil {
db, err := sql.Open("postgres", ps.DataSource)
if err != nil {
- logger(nil).WithError(err).
Fatal
("sql.Open failed")
+ logger(nil).WithError(err).
Error
("sql.Open failed")
return
}
return
}
+ if ps.MaxOpenConns <= 0 {
+ logger(nil).Warn("no database connection limit configured -- consider setting PostgresPool>0 in arvados-ws configuration file")
+ }
+ db.SetMaxOpenConns(ps.MaxOpenConns)
if err = db.Ping(); err != nil {
if err = db.Ping(); err != nil {
- logger(nil).WithError(err).
Fatal
("db.Ping failed")
+ logger(nil).WithError(err).
Error
("db.Ping failed")
return
}
ps.db = db
return
}
ps.db = db
@@
-113,12
+133,15
@@
func (ps *pgEventSource) Run() {
ps.pqListener = pq.NewListener(ps.DataSource, time.Second, time.Minute, ps.listenerProblem)
err = ps.pqListener.Listen("logs")
if err != nil {
ps.pqListener = pq.NewListener(ps.DataSource, time.Second, time.Minute, ps.listenerProblem)
err = ps.pqListener.Listen("logs")
if err != nil {
- logger(nil).WithError(err).Fatal("pq Listen failed")
+ logger(nil).WithError(err).Error("pq Listen failed")
+ return
}
defer ps.pqListener.Close()
logger(nil).Debug("pq Listen setup done")
}
defer ps.pqListener.Close()
logger(nil).Debug("pq Listen setup done")
- close(ps.ready)
+ close(ready)
+ // Avoid double-close in deferred func
+ ready = nil
ps.queue = make(chan *event, ps.QueueSize)
defer close(ps.queue)
ps.queue = make(chan *event, ps.QueueSize)
defer close(ps.queue)
@@
-220,9
+243,17
@@
func (ps *pgEventSource) NewSink() eventSink {
}
func (ps *pgEventSource) DB() *sql.DB {
}
func (ps *pgEventSource) DB() *sql.DB {
+ ps.WaitReady()
return ps.db
}
return ps.db
}
+func (ps *pgEventSource) DBHealth() error {
+ ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(time.Second))
+ defer cancel()
+ var i int
+ return ps.db.QueryRowContext(ctx, "SELECT 1").Scan(&i)
+}
+
func (ps *pgEventSource) DebugStatus() interface{} {
ps.mtx.Lock()
defer ps.mtx.Unlock()
func (ps *pgEventSource) DebugStatus() interface{} {
ps.mtx.Lock()
defer ps.mtx.Unlock()
@@
-238,6
+269,7
@@
func (ps *pgEventSource) DebugStatus() interface{} {
"QueueDelay": stats.Duration(ps.lastQDelay),
"Sinks": len(ps.sinks),
"SinksBlocked": blocked,
"QueueDelay": stats.Duration(ps.lastQDelay),
"Sinks": len(ps.sinks),
"SinksBlocked": blocked,
+ "DBStats": ps.db.Stats(),
}
}
}
}