Skip to content

Commit

Permalink
feat: expose reservation usage stats on jobs (#524)
Browse files Browse the repository at this point in the history
* feat: expose reservation usage stats on jobs

* Add ReservationUsage to job types in docs

* Remove redundant space in docstring.
  • Loading branch information
plamut committed Feb 17, 2021
1 parent edd3328 commit 4ffb4e0
Show file tree
Hide file tree
Showing 4 changed files with 54 additions and 0 deletions.
1 change: 1 addition & 0 deletions docs/reference.rst
Expand Up @@ -62,6 +62,7 @@ Job-Related Types
job.QueryPlanEntry
job.QueryPlanEntryStep
job.QueryPriority
job.ReservationUsage
job.SourceFormat
job.WriteDisposition
job.SchemaUpdateOption
Expand Down
2 changes: 2 additions & 0 deletions google/cloud/bigquery/job/__init__.py
Expand Up @@ -19,6 +19,7 @@
from google.cloud.bigquery.job.base import _DONE_STATE
from google.cloud.bigquery.job.base import _JobConfig
from google.cloud.bigquery.job.base import _JobReference
from google.cloud.bigquery.job.base import ReservationUsage
from google.cloud.bigquery.job.base import ScriptStatistics
from google.cloud.bigquery.job.base import ScriptStackFrame
from google.cloud.bigquery.job.base import UnknownJob
Expand Down Expand Up @@ -51,6 +52,7 @@
"_DONE_STATE",
"_JobConfig",
"_JobReference",
"ReservationUsage",
"ScriptStatistics",
"ScriptStackFrame",
"UnknownJob",
Expand Down
27 changes: 27 additions & 0 deletions google/cloud/bigquery/job/base.py
Expand Up @@ -14,6 +14,7 @@

"""Base classes and helpers for job classes."""

from collections import namedtuple
import copy
import http
import threading
Expand Down Expand Up @@ -73,6 +74,16 @@ def _error_result_to_exception(error_result):
)


ReservationUsage = namedtuple("ReservationUsage", "name slot_ms")
ReservationUsage.__doc__ = "Job resource usage for a reservation."
ReservationUsage.name.__doc__ = (
'Reservation name or "unreserved" for on-demand resources usage.'
)
ReservationUsage.slot_ms.__doc__ = (
"Total slot milliseconds used by the reservation for a particular job."
)


class _JobReference(object):
"""A reference to a job.
Expand Down Expand Up @@ -305,6 +316,22 @@ def _job_statistics(self):
statistics = self._properties.get("statistics", {})
return statistics.get(self._JOB_TYPE, {})

@property
def reservation_usage(self):
"""Job resource usage breakdown by reservation.
Returns:
List[google.cloud.bigquery.job.ReservationUsage]:
Reservation usage stats. Can be empty if not set from the server.
"""
usage_stats_raw = _helpers._get_sub_prop(
self._properties, ["statistics", "reservationUsage"], default=()
)
return [
ReservationUsage(name=usage["name"], slot_ms=int(usage["slotMs"]))
for usage in usage_stats_raw
]

@property
def error_result(self):
"""Error information about the job as a whole.
Expand Down
24 changes: 24 additions & 0 deletions tests/unit/job/test_base.py
Expand Up @@ -319,6 +319,30 @@ def test_ended(self):
stats["endTime"] = millis
self.assertEqual(job.ended, now)

def test_reservation_usage_no_stats(self):
client = _make_client(project=self.PROJECT)
job = self._make_one(self.JOB_ID, client)
job._properties["statistics"] = {}
self.assertEqual(job.reservation_usage, [])

def test_reservation_usage_stats_exist(self):
from google.cloud.bigquery.job import ReservationUsage

client = _make_client(project=self.PROJECT)
job = self._make_one(self.JOB_ID, client)
job._properties["statistics"] = {
"reservationUsage": [
{"name": "slot_foo", "slotMs": "42"},
{"name": "slot_bar", "slotMs": "123"},
],
}

expected = [
ReservationUsage(name="slot_foo", slot_ms=42),
ReservationUsage(name="slot_bar", slot_ms=123),
]
self.assertEqual(job.reservation_usage, expected)

def test__job_statistics(self):
statistics = {"foo": "bar"}
client = _make_client(project=self.PROJECT)
Expand Down

0 comments on commit 4ffb4e0

Please sign in to comment.