diff --git a/functions/bigtable/main_async.py b/functions/bigtable/main_async.py new file mode 100644 index 000000000000..ccbf7a001b97 --- /dev/null +++ b/functions/bigtable/main_async.py @@ -0,0 +1,64 @@ +# Copyright 2024 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the 'License'); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an 'AS IS' BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# [START bigtable_functions_quickstart_asyncio] +import asyncio + +import functions_framework +from google.cloud.bigtable.data import BigtableDataClientAsync, ReadRowsQuery, RowRange + +event_loop = asyncio.new_event_loop() +asyncio.set_event_loop(event_loop) + + +# Setup: create a shared client within the context of the event loop +async def create_client(): + # create client in the asyncio event loop context to + # give background tasks a chance to initialize + return BigtableDataClientAsync() + + +client = event_loop.run_until_complete(create_client()) + + +# Actual cloud functions entrypoint, will delegate to the async one +@functions_framework.http +def bigtable_read_data(request): + return event_loop.run_until_complete(_bigtable_read_data_async(request)) + + +# Actual handler +async def _bigtable_read_data_async(request): + async with client.get_table( + request.headers.get("instance_id"), request.headers.get("table_id") + ) as table: + + prefix = "phone#" + end_key = prefix[:-1] + chr(ord(prefix[-1]) + 1) + + outputs = [] + query = ReadRowsQuery(row_ranges=[RowRange(start_key=prefix, end_key=end_key)]) + + async for row in await table.read_rows_stream(query): + print("%s" % row) + output = "Rowkey: {}, os_build: {}".format( + row.row_key.decode("utf-8"), + row.get_cells("stats_summary", b"os_build")[0].value.decode("utf-8"), + ) + outputs.append(output) + + return "\n".join(outputs) + + +# [END bigtable_functions_quickstart_asyncio] diff --git a/functions/bigtable/main_async_test.py b/functions/bigtable/main_async_test.py new file mode 100644 index 000000000000..963cbf249d92 --- /dev/null +++ b/functions/bigtable/main_async_test.py @@ -0,0 +1,69 @@ +# Copyright 2024 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the 'License'); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an 'AS IS' BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import datetime +import os +import uuid + +from google.cloud import bigtable +import pytest +from requests import Request + +import main_async + +PROJECT = os.environ["GOOGLE_CLOUD_PROJECT"] +BIGTABLE_INSTANCE = os.environ["BIGTABLE_INSTANCE"] +TABLE_ID_PREFIX = "mobile-time-series-{}" + + +@pytest.fixture(scope="module", autouse=True) +def table_id(): + client = bigtable.Client(project=PROJECT, admin=True) + instance = client.instance(BIGTABLE_INSTANCE) + + table_id = TABLE_ID_PREFIX.format(str(uuid.uuid4())[:16]) + table = instance.table(table_id) + if table.exists(): + table.delete() + + table.create(column_families={"stats_summary": None}) + + timestamp = datetime.datetime(2019, 5, 1) + rows = [ + table.direct_row("phone#4c410523#20190501"), + table.direct_row("phone#4c410523#20190502"), + ] + + rows[0].set_cell("stats_summary", "os_build", "PQ2A.190405.003", timestamp) + rows[1].set_cell("stats_summary", "os_build", "PQ2A.190405.004", timestamp) + + table.mutate_rows(rows) + + yield table_id + + table.delete() + + +def test_main(table_id): + request = Request( + "GET", headers={"instance_id": BIGTABLE_INSTANCE, "table_id": table_id} + ) + + response = main_async.bigtable_read_data(request) + + assert ( + """Rowkey: phone#4c410523#20190501, os_build: PQ2A.190405.003 +Rowkey: phone#4c410523#20190502, os_build: PQ2A.190405.004""" + in response + ) diff --git a/functions/bigtable/requirements.txt b/functions/bigtable/requirements.txt index 4802c7deebfc..67201ab950bb 100644 --- a/functions/bigtable/requirements.txt +++ b/functions/bigtable/requirements.txt @@ -1 +1,2 @@ -google-cloud-bigtable==2.19.0 +functions-framework==3.7.0 +google-cloud-bigtable==2.23.1