Skip to content

Commit 0179d1e

Browse files
committed
Merge branch '102-check-activity-for-idle-clones' into 'master'
feat: take into account active connections while determining idle clones. (#102) See merge request postgres-ai/database-lab!76
2 parents 0d4f058 + 23f3cb2 commit 0179d1e

File tree

3 files changed

+53
-9
lines changed

3 files changed

+53
-9
lines changed

pkg/services/cloning/mode_base.go

Lines changed: 45 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,20 +6,22 @@ package cloning
66

77
import (
88
"context"
9+
"database/sql"
910
"fmt"
1011
"strconv"
1112
"strings"
1213
"sync"
1314
"time"
1415

16+
_ "github.com/lib/pq" // Register Postgres database driver.
17+
"github.com/pkg/errors"
18+
"github.com/rs/xid"
19+
1520
"gitlab.com/postgres-ai/database-lab/pkg/log"
1621
"gitlab.com/postgres-ai/database-lab/pkg/models"
1722
"gitlab.com/postgres-ai/database-lab/pkg/services/provision"
1823
"gitlab.com/postgres-ai/database-lab/pkg/util"
1924
"gitlab.com/postgres-ai/database-lab/pkg/util/pglog"
20-
21-
"github.com/pkg/errors"
22-
"github.com/rs/xid"
2325
)
2426

2527
const idleCheckDuration = 5 * time.Minute
@@ -497,6 +499,7 @@ func (c *baseCloning) destroyIdleClones(ctx context.Context) {
497499
}
498500
}
499501

502+
// isIdleClone checks if clone is idle.
500503
func (c *baseCloning) isIdleClone(wrapper *CloneWrapper) (bool, error) {
501504
currentTime := time.Now()
502505

@@ -520,7 +523,7 @@ func (c *baseCloning) isIdleClone(wrapper *CloneWrapper) (bool, error) {
520523
log.Dbg(fmt.Sprintf("Not found recent activity for the session: %q. Session name: %q",
521524
session.ID, session.Name))
522525

523-
return true, nil
526+
return hasNotQueryActivity(session)
524527
}
525528

526529
return false, errors.Wrap(err, "failed to get the last session activity")
@@ -532,5 +535,42 @@ func (c *baseCloning) isIdleClone(wrapper *CloneWrapper) (bool, error) {
532535
return false, nil
533536
}
534537

535-
return true, nil
538+
return hasNotQueryActivity(session)
539+
}
540+
541+
const pgDriverName = "postgres"
542+
543+
// hasNotQueryActivity opens connection and checks if there is no any query running by a user.
544+
func hasNotQueryActivity(session *provision.Session) (bool, error) {
545+
log.Dbg(fmt.Sprintf("Check an active query for: %q.", session.ID))
546+
547+
db, err := sql.Open(pgDriverName, getSocketConnStr(session))
548+
549+
if err != nil {
550+
return false, errors.Wrap(err, "cannot connect to database")
551+
}
552+
553+
defer func() {
554+
if err := db.Close(); err != nil {
555+
log.Err("Cannot close database connection.")
556+
}
557+
}()
558+
559+
return checkActiveQueryNotExists(db)
560+
}
561+
562+
// TODO(akartasov): Move the function to the provision service.
563+
func getSocketConnStr(session *provision.Session) string {
564+
return fmt.Sprintf("host=%s user=%s", session.SocketHost, session.User)
565+
}
566+
567+
// checkActiveQueryNotExists runs query to check a user activity.
568+
func checkActiveQueryNotExists(db *sql.DB) (bool, error) {
569+
var isRunningQueryNotExists bool
570+
571+
query := `SELECT NOT EXISTS(
572+
SELECT * FROM pg_stat_activity WHERE state NOT ILIKE 'idle%' AND query NOT LIKE 'autovacuum: %' AND pid <> pg_backend_pid())`
573+
err := db.QueryRow(query).Scan(&isRunningQueryNotExists)
574+
575+
return isRunningQueryNotExists, err
536576
}

pkg/services/provision/mode_zfs.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,13 +233,16 @@ func (j *provisionModeZfs) StartSession(username, password, snapshotID string) (
233233

234234
j.sessionCounter++
235235

236+
pgConfig := j.getPgConfig(name, port)
237+
236238
session := &Session{
237239
ID: strconv.FormatUint(uint64(j.sessionCounter), 10),
238240

239241
Host: DefaultHost,
240242
Port: port,
241243
User: j.config.PgMgmtUsername,
242244
Password: j.config.PgMgmtPassword,
245+
SocketHost: pgConfig.Host,
243246
ephemeralUser: username,
244247
ephemeralPassword: password,
245248
}

pkg/services/provision/provision.go

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,11 @@ type Session struct {
4040
Name string
4141

4242
// Database.
43-
Host string
44-
Port uint
45-
User string
46-
Password string
43+
Host string
44+
Port uint
45+
User string
46+
Password string
47+
SocketHost string
4748

4849
// For user-defined username and password.
4950
ephemeralUser string

0 commit comments

Comments
 (0)