Skip to content

Commit 06a2f27

Browse files
authored
Merge pull request #1632 from ydb-platform/fix-close
check context before call session close
2 parents dd9f27b + 54669b4 commit 06a2f27

File tree

7 files changed

+65
-52
lines changed

7 files changed

+65
-52
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
* Fixed bug with wrong context on session closing
12
* Fixed goroutine leak on closing `database/sql` driver
23
* "No endpoints" is retriable error now
34

internal/query/session_core.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,10 @@ func (core *sessionCore) deleteSession(ctx context.Context) (finalErr error) {
240240
defer cancel()
241241
}
242242

243+
if err := ctx.Err(); err != nil {
244+
return xerrors.WithStackTrace(err)
245+
}
246+
243247
_, err := core.Client.DeleteSession(ctx,
244248
&Ydb_Query.DeleteSessionRequest{
245249
SessionId: core.id,

internal/table/retry_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,11 +88,11 @@ func TestDoBadSession(t *testing.T) {
8888
p := pool.New[*Session, Session](ctx,
8989
pool.WithCreateItemFunc[*Session, Session](func(ctx context.Context) (*Session, error) {
9090
s := simpleSession(t)
91-
s.onClose = append(s.onClose, func(s *Session) error {
91+
s.closeOnce = func(_ context.Context) error {
9292
closed[s] = true
9393

9494
return nil
95-
})
95+
}
9696

9797
return s, nil
9898
}),

internal/table/session.go

Lines changed: 51 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ import (
3535
"github.com/ydb-platform/ydb-go-sdk/v3/internal/value"
3636
"github.com/ydb-platform/ydb-go-sdk/v3/internal/xcontext"
3737
"github.com/ydb-platform/ydb-go-sdk/v3/internal/xerrors"
38+
"github.com/ydb-platform/ydb-go-sdk/v3/internal/xsync"
3839
"github.com/ydb-platform/ydb-go-sdk/v3/retry"
3940
"github.com/ydb-platform/ydb-go-sdk/v3/table"
4041
"github.com/ydb-platform/ydb-go-sdk/v3/table/options"
@@ -248,7 +249,7 @@ var (
248249
// Note that after session is no longer needed it should be destroyed by
249250
// Close() call.
250251
type Session struct {
251-
onClose []func(s *Session) error
252+
closeOnce func(ctx context.Context) error
252253
id string
253254
client Ydb_Table_V1.TableServiceClient
254255
status table.SessionStatus
@@ -329,7 +330,7 @@ func newSession(ctx context.Context, cc grpc.ClientConnInterface, config *config
329330
return newTableSession(ctx, cc, config)
330331
}
331332

332-
func newTableSession( //nolint:funlen
333+
func newTableSession(
333334
ctx context.Context, cc grpc.ClientConnInterface, config *config.Config,
334335
) (*Session, error) {
335336
response, err := Ydb_Table_V1.NewTableServiceClient(cc).CreateSession(ctx,
@@ -355,25 +356,6 @@ func newTableSession( //nolint:funlen
355356
id: result.GetSessionId(),
356357
config: config,
357358
status: table.SessionReady,
358-
onClose: []func(s *Session) error{
359-
func(s *Session) error {
360-
_, err = s.client.DeleteSession(ctx,
361-
&Ydb_Table.DeleteSessionRequest{
362-
SessionId: s.id,
363-
OperationParams: operation.Params(ctx,
364-
s.config.OperationTimeout(),
365-
s.config.OperationCancelAfter(),
366-
operation.ModeSync,
367-
),
368-
},
369-
)
370-
if err != nil {
371-
return xerrors.WithStackTrace(err)
372-
}
373-
374-
return nil
375-
},
376-
},
377359
}
378360

379361
s.lastUsage.Store(time.Now().Unix())
@@ -387,6 +369,7 @@ func newTableSession( //nolint:funlen
387369
},
388370
),
389371
)
372+
s.closeOnce = xsync.OnceFunc(closeTableSession(s.client, s.config, s.id))
390373
s.dataQuery = tableClientExecutor{
391374
client: s.client,
392375
ignoreTruncated: s.config.IgnoreTruncated(),
@@ -395,7 +378,37 @@ func newTableSession( //nolint:funlen
395378
return s, nil
396379
}
397380

398-
func newQuerySession( //nolint:funlen
381+
func closeTableSession(c Ydb_Table_V1.TableServiceClient, cfg *config.Config, id string) func(context.Context) error {
382+
return func(ctx context.Context) error {
383+
if err := ctx.Err(); err != nil {
384+
return xerrors.WithStackTrace(err)
385+
}
386+
387+
if t := cfg.DeleteTimeout(); t > 0 {
388+
var cancel context.CancelFunc
389+
ctx, cancel = xcontext.WithTimeout(ctx, t)
390+
defer cancel()
391+
}
392+
393+
_, err := c.DeleteSession(ctx,
394+
&Ydb_Table.DeleteSessionRequest{
395+
SessionId: id,
396+
OperationParams: operation.Params(ctx,
397+
cfg.OperationTimeout(),
398+
cfg.OperationCancelAfter(),
399+
operation.ModeSync,
400+
),
401+
},
402+
)
403+
if err != nil {
404+
return xerrors.WithStackTrace(err)
405+
}
406+
407+
return nil
408+
}
409+
}
410+
411+
func newQuerySession(
399412
ctx context.Context, cc grpc.ClientConnInterface, config *config.Config,
400413
) (*Session, error) {
401414
s := &Session{
@@ -438,16 +451,7 @@ func newQuerySession( //nolint:funlen
438451
},
439452
),
440453
)
441-
s.onClose = []func(s *Session) error{
442-
func(s *Session) error {
443-
err := core.Close(ctx)
444-
if err != nil {
445-
return xerrors.WithStackTrace(err)
446-
}
447-
448-
return nil
449-
},
450-
}
454+
s.closeOnce = xsync.OnceFunc(closeQuerySession(core))
451455
if config.ExecuteDataQueryOverQueryService() {
452456
s.dataQuery = queryClientExecutor{
453457
core: core,
@@ -463,6 +467,17 @@ func newQuerySession( //nolint:funlen
463467
return s, nil
464468
}
465469

470+
func closeQuerySession(core query.Core) func(context.Context) error {
471+
return func(ctx context.Context) error {
472+
err := core.Close(ctx)
473+
if err != nil {
474+
return xerrors.WithStackTrace(err)
475+
}
476+
477+
return nil
478+
}
479+
}
480+
466481
func (s *Session) ID() string {
467482
if s == nil {
468483
return ""
@@ -471,18 +486,18 @@ func (s *Session) ID() string {
471486
return s.id
472487
}
473488

474-
func (s *Session) Close(ctx context.Context) (err error) {
489+
func (s *Session) Close(ctx context.Context) (finalErr error) {
475490
onDone := trace.TableOnSessionDelete(s.config.Trace(), &ctx,
476491
stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/v3/internal/table.(*Session).Close"),
477492
s,
478493
)
479494
defer func() {
480-
onDone(err)
495+
onDone(finalErr)
481496
s.SetStatus(table.SessionClosed)
482497
}()
483498

484-
for _, onClose := range s.onClose {
485-
err := onClose(s)
499+
if s.closeOnce != nil {
500+
err := s.closeOnce(ctx)
486501
if err != nil {
487502
return xerrors.WithStackTrace(err)
488503
}

internal/xsql/connector.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,7 @@ func (c *Connector) Parent() ydbDriver {
200200
func (c *Connector) Close() error {
201201
select {
202202
case <-c.done:
203-
return xerrors.WithStackTrace(errAlreadyClosed)
203+
return nil
204204
default:
205205
close(c.done)
206206

internal/xsql/errors.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import (
1010
var (
1111
ErrUnsupported = driver.ErrSkip
1212
errDeprecated = driver.ErrSkip
13-
errAlreadyClosed = errors.New("already closed")
1413
errWrongQueryProcessor = errors.New("wrong query processor")
1514
errNotReadyConn = xerrors.Retryable(errors.New("iface not ready"), xerrors.InvalidObject())
1615
)

tests/integration/basic_example_database_sql_test.go

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -46,14 +46,12 @@ func TestBasicExampleDatabaseSql(t *testing.T) {
4646
db, err := sql.Open("ydb", os.Getenv("YDB_CONNECTION_STRING"))
4747
require.NoError(t, err)
4848

49-
err = db.PingContext(ctx)
50-
require.NoError(t, err)
49+
require.NoError(t, db.PingContext(ctx))
5150

5251
_, err = ydb.Unwrap(db)
5352
require.NoError(t, err)
5453

55-
err = db.Close()
56-
require.NoError(t, err)
54+
require.NoError(t, db.Close())
5755
})
5856

5957
t.Run("sql.OpenDB", func(t *testing.T) {
@@ -64,26 +62,22 @@ func TestBasicExampleDatabaseSql(t *testing.T) {
6462
require.NoError(t, err)
6563

6664
defer func() {
67-
// cleanup
68-
_ = nativeDriver.Close(ctx)
65+
require.NoError(t, nativeDriver.Close(ctx))
6966
}()
7067

7168
c, err := ydb.Connector(nativeDriver)
7269
require.NoError(t, err)
7370

7471
defer func() {
75-
// cleanup
76-
_ = c.Close()
72+
require.NoError(t, c.Close())
7773
}()
7874

7975
db := sql.OpenDB(c)
8076
defer func() {
81-
// cleanup
82-
_ = db.Close()
77+
require.NoError(t, db.Close())
8378
}()
8479

85-
err = db.PingContext(ctx)
86-
require.NoError(t, err)
80+
require.NoError(t, db.PingContext(ctx))
8781

8882
db.SetMaxOpenConns(50)
8983
db.SetMaxIdleConns(50)

0 commit comments

Comments
 (0)