Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 0179d1e

Browse filesBrowse 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
Copy full SHA for 0179d1e

File tree

3 files changed

+53
-9
lines changed
Filter options

3 files changed

+53
-9
lines changed

‎pkg/services/cloning/mode_base.go

Copy file name to clipboardExpand all lines: pkg/services/cloning/mode_base.go
+45-5Lines 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

Copy file name to clipboardExpand all lines: pkg/services/provision/mode_zfs.go
+3Lines 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

Copy file name to clipboardExpand all lines: pkg/services/provision/provision.go
+5-4Lines 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 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.