garf-executors 0.1.0__tar.gz → 0.1.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {garf_executors-0.1.0 → garf_executors-0.1.3}/PKG-INFO +1 -1
- {garf_executors-0.1.0 → garf_executors-0.1.3}/garf_executors/__init__.py +10 -3
- {garf_executors-0.1.0 → garf_executors-0.1.3}/garf_executors/api_executor.py +8 -1
- {garf_executors-0.1.0 → garf_executors-0.1.3}/garf_executors/entrypoints/cli.py +26 -5
- {garf_executors-0.1.0 → garf_executors-0.1.3}/garf_executors/entrypoints/server.py +1 -1
- {garf_executors-0.1.0 → garf_executors-0.1.3}/garf_executors/entrypoints/tracer.py +4 -6
- {garf_executors-0.1.0 → garf_executors-0.1.3}/garf_executors/execution_context.py +2 -2
- {garf_executors-0.1.0 → garf_executors-0.1.3}/garf_executors/executor.py +30 -15
- {garf_executors-0.1.0 → garf_executors-0.1.3}/garf_executors.egg-info/PKG-INFO +1 -1
- {garf_executors-0.1.0 → garf_executors-0.1.3}/README.md +0 -0
- {garf_executors-0.1.0 → garf_executors-0.1.3}/garf_executors/bq_executor.py +0 -0
- {garf_executors-0.1.0 → garf_executors-0.1.3}/garf_executors/config.py +0 -0
- {garf_executors-0.1.0 → garf_executors-0.1.3}/garf_executors/entrypoints/__init__.py +0 -0
- {garf_executors-0.1.0 → garf_executors-0.1.3}/garf_executors/entrypoints/utils.py +0 -0
- {garf_executors-0.1.0 → garf_executors-0.1.3}/garf_executors/exceptions.py +0 -0
- {garf_executors-0.1.0 → garf_executors-0.1.3}/garf_executors/fetchers.py +0 -0
- {garf_executors-0.1.0 → garf_executors-0.1.3}/garf_executors/sql_executor.py +0 -0
- {garf_executors-0.1.0 → garf_executors-0.1.3}/garf_executors/telemetry.py +0 -0
- {garf_executors-0.1.0 → garf_executors-0.1.3}/garf_executors.egg-info/SOURCES.txt +0 -0
- {garf_executors-0.1.0 → garf_executors-0.1.3}/garf_executors.egg-info/dependency_links.txt +0 -0
- {garf_executors-0.1.0 → garf_executors-0.1.3}/garf_executors.egg-info/entry_points.txt +0 -0
- {garf_executors-0.1.0 → garf_executors-0.1.3}/garf_executors.egg-info/requires.txt +0 -0
- {garf_executors-0.1.0 → garf_executors-0.1.3}/garf_executors.egg-info/top_level.txt +0 -0
- {garf_executors-0.1.0 → garf_executors-0.1.3}/pyproject.toml +0 -0
- {garf_executors-0.1.0 → garf_executors-0.1.3}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: garf-executors
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.3
|
|
4
4
|
Summary: Executes queries against API and writes data to local/remote storage.
|
|
5
5
|
Author-email: "Google Inc. (gTech gPS CSE team)" <no-reply@google.com>, Andrei Markin <andrey.markin.ppc@gmail.com>
|
|
6
6
|
License: Apache 2.0
|
|
@@ -24,7 +24,10 @@ from garf_executors.telemetry import tracer
|
|
|
24
24
|
|
|
25
25
|
@tracer.start_as_current_span('setup_executor')
|
|
26
26
|
def setup_executor(
|
|
27
|
-
source: str,
|
|
27
|
+
source: str,
|
|
28
|
+
fetcher_parameters: dict[str, str | int | bool],
|
|
29
|
+
enable_cache: bool = False,
|
|
30
|
+
cache_ttl_seconds: int = 3600,
|
|
28
31
|
) -> type[executor.Executor]:
|
|
29
32
|
"""Initializes executors based on a source and parameters."""
|
|
30
33
|
if source == 'bq':
|
|
@@ -40,7 +43,11 @@ def setup_executor(
|
|
|
40
43
|
else:
|
|
41
44
|
concrete_api_fetcher = fetchers.get_report_fetcher(source)
|
|
42
45
|
query_executor = ApiQueryExecutor(
|
|
43
|
-
concrete_api_fetcher(
|
|
46
|
+
concrete_api_fetcher(
|
|
47
|
+
**fetcher_parameters,
|
|
48
|
+
enable_cache=enable_cache,
|
|
49
|
+
cache_ttl_seconds=cache_ttl_seconds,
|
|
50
|
+
)
|
|
44
51
|
)
|
|
45
52
|
return query_executor
|
|
46
53
|
|
|
@@ -50,4 +57,4 @@ __all__ = [
|
|
|
50
57
|
'ApiExecutionContext',
|
|
51
58
|
]
|
|
52
59
|
|
|
53
|
-
__version__ = '0.1.
|
|
60
|
+
__version__ = '0.1.3'
|
|
@@ -20,9 +20,11 @@ GarfReport and saving it to local/remote storage.
|
|
|
20
20
|
|
|
21
21
|
from __future__ import annotations
|
|
22
22
|
|
|
23
|
+
import asyncio
|
|
23
24
|
import logging
|
|
24
25
|
|
|
25
26
|
from garf_core import report_fetcher
|
|
27
|
+
from opentelemetry import trace
|
|
26
28
|
|
|
27
29
|
from garf_executors import exceptions, execution_context, executor, fetchers
|
|
28
30
|
from garf_executors.telemetry import tracer
|
|
@@ -76,7 +78,7 @@ class ApiQueryExecutor(executor.Executor):
|
|
|
76
78
|
Returns:
|
|
77
79
|
Result of writing the report.
|
|
78
80
|
"""
|
|
79
|
-
return await self.execute
|
|
81
|
+
return await asyncio.to_thread(self.execute, query, title, context)
|
|
80
82
|
|
|
81
83
|
@tracer.start_as_current_span('api.execute')
|
|
82
84
|
def execute(
|
|
@@ -98,7 +100,12 @@ class ApiQueryExecutor(executor.Executor):
|
|
|
98
100
|
Raises:
|
|
99
101
|
GarfExecutorError: When failed to execute query.
|
|
100
102
|
"""
|
|
103
|
+
span = trace.get_current_span()
|
|
104
|
+
span.set_attribute('fetcher', self.fetcher.__class__.__name__)
|
|
105
|
+
span.set_attribute('api_client', self.fetcher.api_client.__class__.__name__)
|
|
101
106
|
try:
|
|
107
|
+
span.set_attribute('query_title', title)
|
|
108
|
+
span.set_attribute('query_text', query)
|
|
102
109
|
logger.debug('starting query %s', query)
|
|
103
110
|
results = self.fetcher.fetch(
|
|
104
111
|
query_specification=query,
|
|
@@ -28,8 +28,13 @@ from garf_io import reader
|
|
|
28
28
|
import garf_executors
|
|
29
29
|
from garf_executors import config, exceptions
|
|
30
30
|
from garf_executors.entrypoints import utils
|
|
31
|
+
from garf_executors.entrypoints.tracer import initialize_tracer
|
|
32
|
+
from garf_executors.telemetry import tracer
|
|
31
33
|
|
|
34
|
+
initialize_tracer()
|
|
32
35
|
|
|
36
|
+
|
|
37
|
+
@tracer.start_as_current_span('garf.entrypoints.cli')
|
|
33
38
|
def main():
|
|
34
39
|
parser = argparse.ArgumentParser()
|
|
35
40
|
parser.add_argument('query', nargs='*')
|
|
@@ -49,9 +54,19 @@ def main():
|
|
|
49
54
|
parser.add_argument('--dry-run', dest='dry_run', action='store_true')
|
|
50
55
|
parser.add_argument('-v', '--version', dest='version', action='store_true')
|
|
51
56
|
parser.add_argument(
|
|
52
|
-
'--parallel-threshold', dest='parallel_threshold', default=
|
|
57
|
+
'--parallel-threshold', dest='parallel_threshold', default=10, type=int
|
|
58
|
+
)
|
|
59
|
+
parser.add_argument(
|
|
60
|
+
'--enable-cache', dest='enable_cache', action='store_true'
|
|
61
|
+
)
|
|
62
|
+
parser.add_argument(
|
|
63
|
+
'--cache-ttl-seconds',
|
|
64
|
+
dest='cache_ttl_seconds',
|
|
65
|
+
default=3600,
|
|
66
|
+
type=int,
|
|
53
67
|
)
|
|
54
68
|
parser.set_defaults(parallel_queries=True)
|
|
69
|
+
parser.set_defaults(enable_cache=False)
|
|
55
70
|
parser.set_defaults(dry_run=False)
|
|
56
71
|
args, kwargs = parser.parse_known_args()
|
|
57
72
|
|
|
@@ -74,10 +89,13 @@ def main():
|
|
|
74
89
|
f'No execution context found for source {args.source} in {config_file}'
|
|
75
90
|
)
|
|
76
91
|
query_executor = garf_executors.setup_executor(
|
|
77
|
-
args.source,
|
|
92
|
+
source=args.source,
|
|
93
|
+
fetcher_parameters=context.fetcher_parameters,
|
|
94
|
+
enable_cache=args.enable_cache,
|
|
95
|
+
cache_ttl_seconds=args.cache_ttl_seconds,
|
|
78
96
|
)
|
|
79
97
|
batch = {query: reader_client.read(query) for query in args.query}
|
|
80
|
-
query_executor.execute_batch(batch, context, args.
|
|
98
|
+
query_executor.execute_batch(batch, context, args.parallel_threshold)
|
|
81
99
|
else:
|
|
82
100
|
extra_parameters = utils.ParamsParser(
|
|
83
101
|
['source', args.output, 'macro', 'template']
|
|
@@ -94,12 +112,15 @@ def main():
|
|
|
94
112
|
fetcher_parameters=source_parameters,
|
|
95
113
|
)
|
|
96
114
|
query_executor = garf_executors.setup_executor(
|
|
97
|
-
args.source,
|
|
115
|
+
source=args.source,
|
|
116
|
+
fetcher_parameters=context.fetcher_parameters,
|
|
117
|
+
enable_cache=args.enable_cache,
|
|
118
|
+
cache_ttl_seconds=args.cache_ttl_seconds,
|
|
98
119
|
)
|
|
99
120
|
if args.parallel_queries:
|
|
100
121
|
logger.info('Running queries in parallel')
|
|
101
122
|
batch = {query: reader_client.read(query) for query in args.query}
|
|
102
|
-
query_executor.execute_batch(batch, context, args.
|
|
123
|
+
query_executor.execute_batch(batch, context, args.parallel_threshold)
|
|
103
124
|
else:
|
|
104
125
|
logger.info('Running queries sequentially')
|
|
105
126
|
for query in args.query:
|
|
@@ -94,7 +94,7 @@ async def execute(request: ApiExecutorRequest) -> ApiExecutorResponse:
|
|
|
94
94
|
|
|
95
95
|
|
|
96
96
|
@app.post('/api/execute:batch')
|
|
97
|
-
|
|
97
|
+
def execute_batch(request: ApiExecutorRequest) -> ApiExecutorResponse:
|
|
98
98
|
query_executor = garf_executors.setup_executor(
|
|
99
99
|
request.source, request.context.fetcher_parameters
|
|
100
100
|
)
|
|
@@ -34,11 +34,9 @@ def initialize_tracer():
|
|
|
34
34
|
|
|
35
35
|
tracer_provider = TracerProvider(resource=resource)
|
|
36
36
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
endpoint=
|
|
37
|
+
if otel_endpoint := os.getenv('OTEL_EXPORTER_OTLP_ENDPOINT'):
|
|
38
|
+
otlp_processor = BatchSpanProcessor(
|
|
39
|
+
OTLPSpanExporter(endpoint=otel_endpoint, insecure=True)
|
|
40
40
|
)
|
|
41
|
-
|
|
42
|
-
tracer_provider.add_span_processor(otlp_processor)
|
|
43
|
-
|
|
41
|
+
tracer_provider.add_span_processor(otlp_processor)
|
|
44
42
|
trace.set_tracer_provider(tracer_provider)
|
|
@@ -42,8 +42,8 @@ class ExecutionContext(pydantic.BaseModel):
|
|
|
42
42
|
query_parameters: query_editor.GarfQueryParameters | None = pydantic.Field(
|
|
43
43
|
default_factory=dict
|
|
44
44
|
)
|
|
45
|
-
fetcher_parameters: dict[str, str | list[str | int]] | None =
|
|
46
|
-
default_factory=dict
|
|
45
|
+
fetcher_parameters: dict[str, str | bool | int | list[str | int]] | None = (
|
|
46
|
+
pydantic.Field(default_factory=dict)
|
|
47
47
|
)
|
|
48
48
|
writer: str | None = None
|
|
49
49
|
writer_parameters: dict[str, str] | None = pydantic.Field(
|
|
@@ -14,14 +14,18 @@
|
|
|
14
14
|
|
|
15
15
|
"""Defines common functionality between executors."""
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
import asyncio
|
|
18
|
+
|
|
19
|
+
from opentelemetry import trace
|
|
18
20
|
|
|
19
21
|
from garf_executors import execution_context
|
|
22
|
+
from garf_executors.telemetry import tracer
|
|
20
23
|
|
|
21
24
|
|
|
22
25
|
class Executor:
|
|
23
26
|
"""Defines common functionality between executors."""
|
|
24
27
|
|
|
28
|
+
@tracer.start_as_current_span('api.execute_batch')
|
|
25
29
|
def execute_batch(
|
|
26
30
|
self,
|
|
27
31
|
batch: dict[str, str],
|
|
@@ -38,17 +42,28 @@ class Executor:
|
|
|
38
42
|
Returns:
|
|
39
43
|
Results of execution.
|
|
40
44
|
"""
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
45
|
+
span = trace.get_current_span()
|
|
46
|
+
span.set_attribute('api.parallel_threshold', parallel_threshold)
|
|
47
|
+
return asyncio.run(
|
|
48
|
+
self._run(
|
|
49
|
+
batch=batch, context=context, parallel_threshold=parallel_threshold
|
|
50
|
+
)
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
async def _run(
|
|
54
|
+
self,
|
|
55
|
+
batch: dict[str, str],
|
|
56
|
+
context: execution_context.ExecutionContext,
|
|
57
|
+
parallel_threshold: int,
|
|
58
|
+
):
|
|
59
|
+
semaphore = asyncio.Semaphore(value=parallel_threshold)
|
|
60
|
+
|
|
61
|
+
async def run_with_semaphore(fn):
|
|
62
|
+
async with semaphore:
|
|
63
|
+
return await fn
|
|
64
|
+
|
|
65
|
+
tasks = [
|
|
66
|
+
self.aexecute(query=query, title=title, context=context)
|
|
67
|
+
for title, query in batch.items()
|
|
68
|
+
]
|
|
69
|
+
return await asyncio.gather(*(run_with_semaphore(task) for task in tasks))
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: garf-executors
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.3
|
|
4
4
|
Summary: Executes queries against API and writes data to local/remote storage.
|
|
5
5
|
Author-email: "Google Inc. (gTech gPS CSE team)" <no-reply@google.com>, Andrei Markin <andrey.markin.ppc@gmail.com>
|
|
6
6
|
License: Apache 2.0
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|