Skip to content
This repository was archived by the owner on Apr 1, 2026. It is now read-only.

Commit ae16eee

Browse files
committed
feat: Restore Table LRO rework + async restore table
1 parent 71c3000 commit ae16eee

6 files changed

Lines changed: 569 additions & 66 deletions

File tree

google/cloud/bigtable/admin_v2/overlay/services/bigtable_table_admin/async_client.py

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
)
5353
from google.cloud.bigtable.admin_v2.overlay.types import (
5454
async_consistency,
55+
async_restore_table,
5556
wait_for_consistency_request,
5657
)
5758

@@ -133,6 +134,100 @@ def __init__(
133134
client_info=client_info,
134135
)
135136

137+
async def restore_table(
138+
self,
139+
request: Optional[Union[bigtable_table_admin.RestoreTableRequest, dict]] = None,
140+
*,
141+
retry: OptionalRetry = gapic_v1.method.DEFAULT,
142+
timeout: Union[float, object] = gapic_v1.method.DEFAULT,
143+
metadata: Sequence[Tuple[str, Union[str, bytes]]] = (),
144+
) -> async_restore_table.AsyncRestoreTableOperation:
145+
r"""Create a new table by restoring from a completed backup. The
146+
returned table :class:`long-running operation
147+
<google.cloud.bigtable.admin_v2.overlay.types.restore_table.RestoreTableOperation>`
148+
can be used to track the progress of the operation, and to cancel it. The
149+
:attr:`metadata <google.api_core.operation.Operation.metadata>` field type is
150+
:class:`RestoreTableMetadata <google.cloud.bigtable.admin_v2.types.RestoreTableMetadata>`.
151+
The :meth:`response <google.api_core.operation.Operation.result>` type is
152+
:class:`google.cloud.bigtable.admin_v2.types.Table`, if successful.
153+
154+
Additionally, the returned :class:`long-running-operation <google.cloud.bigtable.admin_v2.overlay.types.async_restore_table.AsyncRestoreTableOperation>`
155+
provides a method, :meth:`google.cloud.bigtable.admin_v2.overlay.types.async_restore_table.AsyncRestoreTableOperation.optimize_restore_table_operation` that
156+
provides access to a :class:`google.api_core.operation_async.AsyncOperation` object representing the OptimizeRestoreTable long-running-operation
157+
after the current one has completed.
158+
159+
.. code-block:: python
160+
161+
# This snippet should be regarded as a code template only.
162+
#
163+
# It will require modifications to work:
164+
# - It may require correct/in-range values for request initialization.
165+
# - It may require specifying regional endpoints when creating the service
166+
# client as shown in:
167+
# https://googleapis.dev/python/google-api-core/latest/client_options.html
168+
from google.cloud.bigtable import admin_v2
169+
170+
async def sample_restore_table():
171+
# Create a client
172+
client = admin_v2.BigtableTableAdminAsyncClient()
173+
174+
# Initialize request argument(s)
175+
request = admin_v2.RestoreTableRequest(
176+
backup="backup_value",
177+
parent="parent_value",
178+
table_id="table_id_value",
179+
)
180+
181+
# Make the request
182+
operation = await client.restore_table(request=request)
183+
184+
print("Waiting for operation to complete...")
185+
186+
response = await operation.result()
187+
188+
# Handle the response
189+
print(response)
190+
191+
# Handle LRO2
192+
optimize_operation = await operation.optimize_restore_table_operation()
193+
194+
if optimize_operation:
195+
print("Waiting for table optimization to complete...")
196+
197+
response = await optimize_operation.result()
198+
199+
Args:
200+
request (Union[google.cloud.bigtable.admin_v2.types.RestoreTableRequest, dict]):
201+
The request object. The request for
202+
[RestoreTable][google.bigtable.admin.v2.BigtableTableAdmin.RestoreTable].
203+
retry (google.api_core.retry.Retry): Designation of what errors, if any,
204+
should be retried.
205+
timeout (float): The timeout for this request.
206+
metadata (Sequence[Tuple[str, Union[str, bytes]]]): Key/value pairs which should be
207+
sent along with the request as metadata. Normally, each value must be of type `str`,
208+
but for metadata keys ending with the suffix `-bin`, the corresponding values must
209+
be of type `bytes`.
210+
211+
Returns:
212+
google.cloud.bigtable.admin_v2.overlay.types.async_restore_table.AsyncRestoreTableOperation:
213+
An object representing a long-running operation.
214+
215+
The result type for the operation will be :class:`google.cloud.bigtable.admin_v2.types.Table` A collection of user data indexed by row, column, and timestamp.
216+
Each table is served using the resources of its
217+
parent cluster.
218+
"""
219+
operation = await self._restore_table(
220+
request=request,
221+
retry=retry,
222+
timeout=timeout,
223+
metadata=metadata,
224+
)
225+
226+
restore_table_operation = async_restore_table.AsyncRestoreTableOperation(
227+
self._client._transport.operations_client, operation
228+
)
229+
return restore_table_operation
230+
136231
async def wait_for_consistency(
137232
self,
138233
request: Optional[
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
# Copyright 2025 Google LLC.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
from typing import Optional
16+
17+
from google.api_core import exceptions
18+
from google.api_core import operation_async
19+
from google.protobuf import empty_pb2
20+
21+
from google.cloud.bigtable.admin_v2.types import OptimizeRestoredTableMetadata
22+
23+
24+
class AsyncRestoreTableOperation(operation_async.AsyncOperation):
25+
"""A Future for interacting with Bigtable Admin's RestoreTable Long-Running Operation.
26+
27+
This is needed to expose a potential long-running operation that might run after this operation
28+
finishes, OptimizeRestoreTable. This is exposed via the the :meth:`optimize_restore_table_operation`
29+
method.
30+
31+
**This class should not be instantiated by users** and should only be instantiated by the admin
32+
client's :meth:`restore_table
33+
<google.cloud.bigtable.admin_v2.overlay.services.bigtable_table_admin.BigtableTableAdminAsyncClient.restore_table>`
34+
method.
35+
36+
Args:
37+
operations_client (google.api_core.operations_v1.AbstractOperationsClient): The operations
38+
client from the admin client class's transport.
39+
restore_table_operation (google.api_core.operation_async.AsyncOperation): A
40+
:class:`google.api_core.operation_async.AsyncOperation`
41+
instance resembling a RestoreTable long-running operation
42+
"""
43+
44+
def __init__(
45+
self, operations_client, restore_table_operation: operation_async.AsyncOperation
46+
):
47+
self._operations_client = operations_client
48+
self._optimize_restored_table_operation = None
49+
super().__init__(
50+
restore_table_operation._operation,
51+
restore_table_operation._refresh,
52+
restore_table_operation._cancel,
53+
restore_table_operation._result_type,
54+
restore_table_operation._metadata_type,
55+
retry=restore_table_operation._retry,
56+
)
57+
58+
async def optimize_restored_table_operation(
59+
self,
60+
) -> Optional[operation_async.AsyncOperation]:
61+
"""Gets the OptimizeRestoredTable long-running operation that runs after this operation finishes.
62+
The current operation might not trigger a follow-up OptimizeRestoredTable operation, in which case, this
63+
method will return `None`.
64+
This method must not be called before the parent restore_table operation is complete.
65+
Returns:
66+
An object representing a long-running operation, or None if there is no OptimizeRestoredTable operation
67+
after this one.
68+
Raises:
69+
RuntimeError: raised when accessed before the restore_table operation is complete
70+
71+
Raises:
72+
google.api_core.GoogleAPIError: raised when accessed before the restore_table operation is complete
73+
"""
74+
if not await self.done():
75+
raise exceptions.GoogleAPIError(
76+
"optimize_restored_table operation can't be accessed until the restore_table operation is complete"
77+
)
78+
79+
if self._optimize_restored_table_operation is not None:
80+
return self._optimize_restored_table_operation
81+
82+
operation_name = self.metadata.optimize_table_operation_name
83+
84+
# When the RestoreTable operation finishes, it might not necessarily trigger
85+
# an optimize operation.
86+
if operation_name:
87+
gapic_operation = await self._operations_client.get_operation(
88+
name=operation_name
89+
)
90+
self._optimize_restored_table_operation = operation_async.from_gapic(
91+
gapic_operation,
92+
self._operations_client,
93+
empty_pb2.Empty,
94+
metadata_type=OptimizeRestoredTableMetadata,
95+
)
96+
return self._optimize_restored_table_operation
97+
else:
98+
# no optimize operation found
99+
return None

google/cloud/bigtable/admin_v2/overlay/types/restore_table.py

Lines changed: 25 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -12,22 +12,15 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15-
import enum
16-
from typing import Optional, Union
15+
from typing import Optional
1716

18-
from google.api_core import retry
17+
from google.api_core import exceptions
1918
from google.api_core import operation
2019
from google.protobuf import empty_pb2
2120

2221
from google.cloud.bigtable.admin_v2.types import OptimizeRestoredTableMetadata
2322

2423

25-
# This is needed due to a documentation issue with using object() as the default
26-
# value for a parameter.
27-
class Timeout(enum.Enum):
28-
DEFAULT_TIMEOUT = "DEFAULT_TIMEOUT"
29-
30-
3124
class RestoreTableOperation(operation.Operation):
3225
"""A Future for interacting with Bigtable Admin's RestoreTable Long-Running Operation.
3326
@@ -59,16 +52,14 @@ def __init__(self, operations_client, restore_table_operation: operation.Operati
5952
polling=restore_table_operation._polling,
6053
)
6154

62-
def optimize_restored_table_operation(
63-
self,
64-
timeout: Optional[Union[int, Timeout]] = Timeout.DEFAULT_TIMEOUT,
65-
retry: Optional[retry.Retry] = None,
66-
polling: Optional[retry.Retry] = None,
67-
) -> Optional[operation.Operation]:
55+
def optimize_restored_table_operation(self) -> Optional[operation.Operation]:
6856
"""Gets the OptimizeRestoredTable long-running operation that runs after this operation finishes.
6957
70-
This is a blocking call that will return the operation after this current long-running operation
71-
finishes, just like :meth:`google.api_core.operation.Operation.result`. The follow-up operation has
58+
This must not be called before the parent restore_table operation is complete. You can guarantee
59+
this happening by calling this function after this class's :meth:`google.api_core.operation.Operation.result`
60+
method.
61+
62+
The follow-up operation has
7263
:attr:`metadata <google.api_core.operation.Operation.metadata>` type
7364
:class:`OptimizeRestoredTableMetadata
7465
<google.cloud.bigtable.admin_v2.types.bigtable_table_admin.OptimizeRestoredTableMetadata>`
@@ -77,51 +68,35 @@ def optimize_restored_table_operation(
7768
The current operation might not trigger a follow-up OptimizeRestoredTable operation, in which case, this
7869
method will return `None`.
7970
80-
Args:
81-
timeout (Optional[int | google.cloud.bigtable.admin_v2.overlay.types.restore_table.Timeout]):
82-
How long (in seconds) to wait for the operation to complete. If None, wait indefinitely. If
83-
`Timeout.DEFAULT_TIMEOUT`, wait the default amount.
84-
retry (Optional[google.api_core.retry.Retry]): How to retry the polling RPC. This defines ONLY
85-
how the polling RPC call is retried (i.e. what to do if the RPC we used for polling returned
86-
an error). It does NOT define how the polling is done (i.e. how frequently and for how long
87-
to call the polling RPC).
88-
polling (Optional[google.api_core.retry.Retry]): How often and for how long to call polling RPC
89-
periodically. This parameter does NOT define how to retry each individual polling RPC call
90-
(use the `retry` parameter for that).
91-
9271
Returns:
9372
Optional[google.api_core.operation.Operation]:
9473
An object representing a long-running operation, or None if there is no OptimizeRestoredTable operation
9574
after this one.
96-
"""
97-
if timeout == Timeout.DEFAULT_TIMEOUT:
98-
timeout = operation.Operation._DEFAULT_VALUE
99-
100-
self._blocking_poll(timeout=timeout, retry=retry, polling=polling)
10175
102-
if self._exception is not None:
103-
# pylint: disable=raising-bad-type
104-
# Pylint doesn't recognize that this is valid in this case.
105-
raise self._exception
76+
Raises:
77+
google.api_core.GoogleAPIError: raised when accessed before the restore_table operation is complete
78+
"""
79+
if not self.done():
80+
raise exceptions.GoogleAPIError(
81+
"optimize_restored_table operation can't be accessed until the restore_table operation is complete"
82+
)
10683

107-
return self._optimize_restored_table_operation
84+
if self._optimize_restored_table_operation is not None:
85+
return self._optimize_restored_table_operation
10886

109-
def set_result(self, response):
110-
optimize_restored_table_operation_name = (
111-
self.metadata.optimize_table_operation_name
112-
)
87+
operation_name = self.metadata.optimize_table_operation_name
11388

11489
# When the RestoreTable operation finishes, it might not necessarily trigger
11590
# an optimize operation.
116-
if optimize_restored_table_operation_name:
117-
optimize_restore_table_operation = self._operations_client.get_operation(
118-
name=optimize_restored_table_operation_name
119-
)
91+
if operation_name:
92+
gapic_operation = self._operations_client.get_operation(name=operation_name)
12093
self._optimize_restored_table_operation = operation.from_gapic(
121-
optimize_restore_table_operation,
94+
gapic_operation,
12295
self._operations_client,
12396
empty_pb2.Empty,
12497
metadata_type=OptimizeRestoredTableMetadata,
12598
)
126-
127-
super().set_result(response)
99+
return self._optimize_restored_table_operation
100+
else:
101+
# no optimize operation found
102+
return None

0 commit comments

Comments
 (0)