Skip to content

Commit 68ca5bc

Browse files
committed
fix(spanner): ensure session pool is bound before database use
1 parent 21e4a73 commit 68ca5bc

20 files changed

+280
-232
lines changed

google/cloud/spanner_v1/_async/database.py

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,8 @@
1414

1515
"""User-friendly container for Cloud Spanner Database."""
1616
__CROSS_SYNC_OUTPUT__ = "google.cloud.spanner_v1.database"
17-
import asyncio
1817
import copy
1918
import functools
20-
import inspect
2119
import logging
2220
import re
2321
import threading
@@ -223,14 +221,8 @@ def __init__(
223221
pool = BurstyPool(database_role=database_role)
224222

225223
self._pool = pool
226-
res = pool.bind(self)
227-
try:
228-
loop = asyncio.get_running_loop()
229-
if loop.is_running() and inspect.isawaitable(res):
230-
loop.create_task(res)
231-
except RuntimeError:
232-
# No running loop, bind should have been sync or will be failed later
233-
pass
224+
# Note: self._pool.bind(self) should be called via Instance.database()
225+
# factory method to ensure proper async initialization.
234226
is_experimental_host = (
235227
self._instance.experimental_host is not None if self._instance else False
236228
)

google/cloud/spanner_v1/_async/instance.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -433,7 +433,8 @@ async def delete(self):
433433

434434
await api.delete_instance(name=self.name, metadata=metadata)
435435

436-
def database(
436+
@CrossSync.convert
437+
async def database(
437438
self,
438439
database_id,
439440
ddl_statements=(),
@@ -498,7 +499,7 @@ def database(
498499
"""
499500

500501
if not enable_interceptors_in_tests:
501-
return Database(
502+
db = Database(
502503
database_id,
503504
self,
504505
ddl_statements=ddl_statements,
@@ -511,7 +512,7 @@ def database(
511512
proto_descriptors=proto_descriptors,
512513
)
513514
else:
514-
return TestDatabase(
515+
db = TestDatabase(
515516
database_id,
516517
self,
517518
ddl_statements=ddl_statements,
@@ -523,6 +524,9 @@ def database(
523524
enable_drop_protection=enable_drop_protection,
524525
)
525526

527+
await db._pool.bind(db)
528+
return db
529+
526530
@CrossSync.convert
527531
async def list_databases(self, page_size=None):
528532
"""List databases for the instance.

google/cloud/spanner_v1/batch.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,9 @@
2020
import functools
2121
import time
2222
from typing import List, Optional
23+
2324
from google.api_core.exceptions import InternalServerError
24-
from google.cloud.spanner_v1._helpers import _retry, _retry_on_aborted_exception
25+
2526
from google.cloud.spanner_v1._helpers import (
2627
AtomicCounter,
2728
_check_rst_stream_error,
@@ -31,6 +32,8 @@
3132
_merge_Transaction_Options,
3233
_metadata_with_leader_aware_routing,
3334
_metadata_with_prefix,
35+
_retry,
36+
_retry_on_aborted_exception,
3437
_SessionWrapper,
3538
_validate_client_context,
3639
)

google/cloud/spanner_v1/client.py

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,34 +32,36 @@
3232
import threading
3333
from typing import Optional
3434
import warnings
35+
3536
import google.api_core.client_options
3637
from google.api_core.gapic_v1 import client_info
3738
from google.auth.credentials import AnonymousCredentials
3839
import grpc
40+
3941
from google.cloud.client import ClientWithProject
4042
from google.cloud.spanner_admin_database_v1 import (
4143
DatabaseAdminClient as DatabaseAdminClient,
4244
)
4345
from google.cloud.spanner_admin_database_v1.services.database_admin.transports.grpc import (
4446
DatabaseAdminGrpcTransport,
4547
)
48+
from google.cloud.spanner_admin_instance_v1 import (
49+
ListInstanceConfigsRequest,
50+
ListInstancesRequest,
51+
)
4652
from google.cloud.spanner_admin_instance_v1 import (
4753
InstanceAdminClient as InstanceAdminClient,
4854
)
4955
from google.cloud.spanner_admin_instance_v1.services.instance_admin.transports.grpc import (
5056
InstanceAdminGrpcTransport,
5157
)
52-
from google.cloud.spanner_admin_instance_v1 import (
53-
ListInstanceConfigsRequest,
54-
ListInstancesRequest,
55-
)
56-
from google.cloud.spanner_v1.instance import Instance
5758
from google.cloud.spanner_v1._helpers import (
5859
_merge_query_options,
5960
_metadata_with_prefix,
6061
_validate_client_context,
6162
)
6263
from google.cloud.spanner_v1.gapic_version import __version__
64+
from google.cloud.spanner_v1.instance import Instance
6365
from google.cloud.spanner_v1.metrics.constants import METRIC_EXPORT_INTERVAL_MS
6466
from google.cloud.spanner_v1.metrics.metrics_exporter import (
6567
CloudMonitoringMetricsExporter,

google/cloud/spanner_v1/database.py

Lines changed: 21 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -17,21 +17,21 @@
1717

1818
"""User-friendly container for Cloud Spanner Database."""
1919

20-
import asyncio
2120
import copy
2221
import functools
23-
import inspect
2422
import logging
2523
import re
2624
import threading
2725
from typing import Optional
26+
2827
from google.api_core import gapic_v1
2928
from google.api_core.exceptions import Aborted
3029
from google.api_core.retry import Retry
3130
import google.auth.credentials
3231
from google.iam.v1 import iam_policy_pb2, options_pb2
3332
from google.protobuf.field_mask_pb2 import FieldMask
3433
import grpc
34+
3535
from google.cloud.aio._cross_sync import CrossSync
3636
from google.cloud.exceptions import NotFound
3737
from google.cloud.spanner_admin_database_v1 import (
@@ -44,15 +44,6 @@
4444
from google.cloud.spanner_admin_database_v1 import CreateDatabaseRequest
4545
from google.cloud.spanner_admin_database_v1 import Database as DatabasePB
4646
from google.cloud.spanner_admin_database_v1.types import DatabaseDialect
47-
from google.cloud.spanner_v1.batch import Batch, MutationGroups
48-
from google.cloud.spanner_v1.database_sessions_manager import (
49-
DatabaseSessionsManager,
50-
TransactionType,
51-
)
52-
from google.cloud.spanner_v1.pool import BurstyPool
53-
from google.cloud.spanner_v1.session import Session
54-
from google.cloud.spanner_v1.snapshot import Snapshot, _restart_on_unavailable
55-
from google.cloud.spanner_v1.streamed import StreamedResultSet
5647
from google.cloud.spanner_v1._helpers import (
5748
_augment_errors_with_request_id,
5849
_merge_query_options,
@@ -61,11 +52,30 @@
6152
_metadata_with_request_id,
6253
_metadata_with_request_id_and_req_id,
6354
)
55+
from google.cloud.spanner_v1._opentelemetry_tracing import (
56+
add_span_event,
57+
get_current_span,
58+
trace_call,
59+
)
60+
from google.cloud.spanner_v1.batch import Batch, MutationGroups
61+
from google.cloud.spanner_v1.database_sessions_manager import (
62+
DatabaseSessionsManager,
63+
TransactionType,
64+
)
6465
from google.cloud.spanner_v1.keyset import KeySet
6566
from google.cloud.spanner_v1.merged_result_set import MergedResultSet
67+
from google.cloud.spanner_v1.metrics.metrics_capture import MetricsCapture
68+
from google.cloud.spanner_v1.pool import BurstyPool
6669
from google.cloud.spanner_v1.services.spanner.client import (
6770
SpannerClient as SpannerClient,
6871
)
72+
from google.cloud.spanner_v1.services.spanner.transports.grpc import (
73+
SpannerGrpcTransport,
74+
)
75+
from google.cloud.spanner_v1.session import Session
76+
from google.cloud.spanner_v1.snapshot import Snapshot, _restart_on_unavailable
77+
from google.cloud.spanner_v1.streamed import StreamedResultSet
78+
from google.cloud.spanner_v1.table import Table
6979
from google.cloud.spanner_v1.transaction import (
7080
BatchTransactionId,
7181
DefaultTransactionOptions,
@@ -76,16 +86,6 @@
7686
TransactionSelector,
7787
)
7888
from google.cloud.spanner_v1.types.type import Type, TypeCode
79-
from google.cloud.spanner_v1.services.spanner.transports.grpc import (
80-
SpannerGrpcTransport,
81-
)
82-
from google.cloud.spanner_v1._opentelemetry_tracing import (
83-
add_span_event,
84-
get_current_span,
85-
trace_call,
86-
)
87-
from google.cloud.spanner_v1.metrics.metrics_capture import MetricsCapture
88-
from google.cloud.spanner_v1.table import Table
8989

9090
SPANNER_DATA_SCOPE = "https://www.googleapis.com/auth/spanner.data"
9191
_DATABASE_NAME_RE = re.compile(
@@ -204,13 +204,6 @@ def __init__(
204204
if pool is None:
205205
pool = BurstyPool(database_role=database_role)
206206
self._pool = pool
207-
res = pool.bind(self)
208-
try:
209-
loop = asyncio.get_running_loop()
210-
if loop.is_running() and inspect.isawaitable(res):
211-
loop.create_task(res)
212-
except RuntimeError:
213-
pass
214207
is_experimental_host = (
215208
self._instance.experimental_host is not None if self._instance else False
216209
)

google/cloud/spanner_v1/database_sessions_manager.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,13 @@
2424
from threading import Thread
2525
from typing import Optional
2626
from weakref import ref
27+
2728
from google.cloud.aio._cross_sync import CrossSync
28-
from google.cloud.spanner_v1.session import Session
2929
from google.cloud.spanner_v1._opentelemetry_tracing import (
3030
add_span_event,
3131
get_current_span,
3232
)
33+
from google.cloud.spanner_v1.session import Session
3334

3435

3536
class TransactionType(Enum):

google/cloud/spanner_v1/instance.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,12 @@
1919

2020
import re
2121
import typing
22+
2223
from google.api_core.exceptions import InvalidArgument
2324
import google.api_core.operation
2425
from google.protobuf.empty_pb2 import Empty
2526
from google.protobuf.field_mask_pb2 import FieldMask
27+
2628
from google.cloud.aio._cross_sync import CrossSync
2729
from google.cloud.exceptions import NotFound
2830
from google.cloud.spanner_admin_database_v1 import (
@@ -34,10 +36,10 @@
3436
)
3537
from google.cloud.spanner_admin_database_v1.types import backup, spanner_database_admin
3638
from google.cloud.spanner_admin_instance_v1 import Instance as InstancePB
37-
from google.cloud.spanner_v1.database import Database
38-
from google.cloud.spanner_v1.testing.database_test import TestDatabase
3939
from google.cloud.spanner_v1._helpers import _metadata_with_prefix
4040
from google.cloud.spanner_v1.backup import Backup
41+
from google.cloud.spanner_v1.database import Database
42+
from google.cloud.spanner_v1.testing.database_test import TestDatabase
4143

4244
_INSTANCE_NAME_RE = re.compile(
4345
"^projects/(?P<project>[^/]+)/instances/(?P<instance_id>[a-z][-a-z0-9]*)$"
@@ -456,7 +458,7 @@ def database(
456458
:rtype: :class:`~google.cloud.spanner_v1.database.Database`
457459
:returns: a database owned by this instance."""
458460
if not enable_interceptors_in_tests:
459-
return Database(
461+
db = Database(
460462
database_id,
461463
self,
462464
ddl_statements=ddl_statements,
@@ -469,7 +471,7 @@ def database(
469471
proto_descriptors=proto_descriptors,
470472
)
471473
else:
472-
return TestDatabase(
474+
db = TestDatabase(
473475
database_id,
474476
self,
475477
ddl_statements=ddl_statements,
@@ -480,6 +482,8 @@ def database(
480482
database_role=database_role,
481483
enable_drop_protection=enable_drop_protection,
482484
)
485+
db._pool.bind(db)
486+
return db
483487

484488
def list_databases(self, page_size=None):
485489
"""List databases for the instance.

google/cloud/spanner_v1/pool.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,9 @@
2121
import datetime
2222
import time
2323
from warnings import warn
24+
2425
from google.cloud.aio._cross_sync import CrossSync
2526
from google.cloud.exceptions import NotFound
26-
from google.cloud.spanner_v1.session import Session
2727
from google.cloud.spanner_v1._helpers import (
2828
_metadata_with_leader_aware_routing,
2929
_metadata_with_prefix,
@@ -34,6 +34,7 @@
3434
trace_call,
3535
)
3636
from google.cloud.spanner_v1.metrics.metrics_capture import MetricsCapture
37+
from google.cloud.spanner_v1.session import Session
3738
from google.cloud.spanner_v1.types.spanner import BatchCreateSessionsRequest
3839
from google.cloud.spanner_v1.types.spanner import Session as SessionProto
3940

google/cloud/spanner_v1/session.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,13 @@
2121
from functools import total_ordering
2222
import time
2323
from typing import MutableMapping, Optional
24+
2425
from google.api_core.exceptions import Aborted, GoogleAPICallError, NotFound
2526
from google.api_core.gapic_v1 import method
27+
2628
from google.cloud.aio._cross_sync import CrossSync
27-
from google.cloud.spanner_v1._helpers import _delay_until_retry
28-
from google.cloud.spanner_v1.batch import Batch
29-
from google.cloud.spanner_v1.snapshot import Snapshot
30-
from google.cloud.spanner_v1.transaction import Transaction
3129
from google.cloud.spanner_v1._helpers import (
30+
_delay_until_retry,
3231
_get_retry_delay,
3332
_metadata_with_leader_aware_routing,
3433
_metadata_with_prefix,
@@ -38,7 +37,10 @@
3837
get_current_span,
3938
trace_call,
4039
)
40+
from google.cloud.spanner_v1.batch import Batch
4141
from google.cloud.spanner_v1.metrics.metrics_capture import MetricsCapture
42+
from google.cloud.spanner_v1.snapshot import Snapshot
43+
from google.cloud.spanner_v1.transaction import Transaction
4244
from google.cloud.spanner_v1.types.spanner import (
4345
CreateSessionRequest,
4446
ExecuteSqlRequest,

google/cloud/spanner_v1/snapshot.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
import functools
2121
from typing import List, Optional, Union
22+
2223
from google.api_core import gapic_v1
2324
from google.api_core.exceptions import (
2425
Aborted,
@@ -27,9 +28,8 @@
2728
ServiceUnavailable,
2829
)
2930
from google.protobuf.struct_pb2 import Struct
31+
3032
from google.cloud.aio._cross_sync import CrossSync
31-
from google.cloud.spanner_v1._helpers import _retry
32-
from google.cloud.spanner_v1.streamed import StreamedResultSet
3333
from google.cloud.spanner_v1._helpers import (
3434
AtomicCounter,
3535
_augment_error_with_request_id,
@@ -40,11 +40,13 @@
4040
_merge_request_options,
4141
_metadata_with_leader_aware_routing,
4242
_metadata_with_prefix,
43+
_retry,
4344
_SessionWrapper,
4445
_validate_client_context,
4546
)
4647
from google.cloud.spanner_v1._opentelemetry_tracing import add_span_event, trace_call
4748
from google.cloud.spanner_v1.metrics.metrics_capture import MetricsCapture
49+
from google.cloud.spanner_v1.streamed import StreamedResultSet
4850
from google.cloud.spanner_v1.types import MultiplexedSessionPrecommitToken
4951
from google.cloud.spanner_v1.types.mutation import Mutation
5052
from google.cloud.spanner_v1.types.result_set import PartialResultSet, ResultSet

0 commit comments

Comments
 (0)