Skip to content

Commit a3aae80

Browse files
keuDmytro Rezchykoveugene-kulak
authored
🎉 🎉 Source FB Marketing: performance and reliability fixes (#9805)
* Facebook Marketing performance improvement * add comments and little refactoring * fix integration tests with the new config * improve job status handling, limit concurrency to 10 * fix campaign jobs, refactor manager * big refactoring of async jobs, support random order of slices * update source _read_incremental to hook new state logic * fix issues with timeout * remove debugging and clean up, improve retry logic * merge changes from #8234 * fix call super _read_increment * generalize batch execution, add use_batch flag * improve coverage, do some refactoring of spec * update test, remove overrides of source * add split by AdSet * add smaller insights * fix end_date < start_date case * add account_id to PK * add notes * fix new streams * fix reversed incremental stream * update spec.json for SAT * upgrade CDK and bump version Co-authored-by: Dmytro Rezchykov <dmitry.rezchykov@zazmic.com> Co-authored-by: Eugene Kulak <kulak.eugene@gmail.com>
1 parent d173ce7 commit a3aae80

36 files changed

+2567
-1517
lines changed

airbyte-config/init/src/main/resources/config/STANDARD_SOURCE_DEFINITION/e7778cfc-e97c-4458-9ecb-b4f2bba8946c.json

Whitespace-only changes.

airbyte-config/init/src/main/resources/seed/source_definitions.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,7 @@
196196
- name: Facebook Marketing
197197
sourceDefinitionId: e7778cfc-e97c-4458-9ecb-b4f2bba8946c
198198
dockerRepository: airbyte/source-facebook-marketing
199-
dockerImageTag: 0.2.33
199+
dockerImageTag: 0.2.34
200200
documentationUrl: https://docs.airbyte.io/integrations/sources/facebook-marketing
201201
icon: facebook.svg
202202
sourceType: api

airbyte-config/init/src/main/resources/seed/source_specs.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1630,7 +1630,7 @@
16301630
supportsNormalization: false
16311631
supportsDBT: false
16321632
supported_destination_sync_modes: []
1633-
- dockerImage: "airbyte/source-facebook-marketing:0.2.33"
1633+
- dockerImage: "airbyte/source-facebook-marketing:0.2.34"
16341634
spec:
16351635
documentationUrl: "https://docs.airbyte.io/integrations/sources/facebook-marketing"
16361636
changelogUrl: "https://docs.airbyte.io/integrations/sources/facebook-marketing"

airbyte-integrations/connectors/source-facebook-marketing/Dockerfile

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,5 @@ RUN pip install .
1212
ENV AIRBYTE_ENTRYPOINT "python /airbyte/integration_code/main.py"
1313
ENTRYPOINT ["python", "/airbyte/integration_code/main.py"]
1414

15-
LABEL io.airbyte.version=0.2.33
15+
LABEL io.airbyte.version=0.2.34
1616
LABEL io.airbyte.name=airbyte/source-facebook-marketing

airbyte-integrations/connectors/source-facebook-marketing/README.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ From the Airbyte repository root, run:
3939
**If you are a community contributor**, follow the instructions in the [documentation](https://docs.airbyte.io/integrations/sources/facebook-marketing)
4040
to generate the necessary credentials. Then create a file `secrets/config.json` conforming to the `source_facebook_marketing/spec.json` file.
4141
Note that any directory named `secrets` is gitignored across the entire Airbyte repo, so there is no danger of accidentally checking in sensitive information.
42-
See `sample_files/sample_config.json` for a sample config file.
42+
See `integration_tests/sample_config.json` for a sample config file.
4343

4444
**If you are an Airbyte core member**, copy the credentials in Lastpass under the secret name `source facebook-marketing test creds`
4545
and place them into `secrets/config.json`.
@@ -73,7 +73,7 @@ Then run any of the connector commands as follows:
7373
docker run --rm airbyte/source-facebook-marketing:dev spec
7474
docker run --rm -v $(pwd)/secrets:/secrets airbyte/source-facebook-marketing:dev check --config /secrets/config.json
7575
docker run --rm -v $(pwd)/secrets:/secrets airbyte/source-facebook-marketing:dev discover --config /secrets/config.json
76-
docker run --rm -v $(pwd)/secrets:/secrets -v $(pwd)/sample_files:/sample_files airbyte/source-facebook-marketing:dev read --config /secrets/config.json --catalog /integration_tests/configured_catalog.json
76+
docker run --rm -v $(pwd)/secrets:/secrets -v $(pwd)/integration_tests:/integration_tests airbyte/source-facebook-marketing:dev read --config /secrets/config.json --catalog /integration_tests/configured_catalog.json
7777
```
7878
## Testing
7979
Make sure to familiarize yourself with [pytest test discovery](https://docs.pytest.org/en/latest/goodpractices.html#test-discovery) to know how your test files and methods should be named.

airbyte-integrations/connectors/source-facebook-marketing/acceptance-test-config.yml

+1-14
Original file line numberDiff line numberDiff line change
@@ -13,23 +13,10 @@ tests:
1313
- config_path: "secrets/config.json"
1414
basic_read:
1515
- config_path: "secrets/config.json"
16-
configured_catalog_path: "integration_tests/configured_catalog.json"
17-
timeout_seconds: 600
16+
empty_streams: ["videos"]
1817
incremental:
1918
- config_path: "secrets/config.json"
2019
configured_catalog_path: "integration_tests/configured_catalog_without_insights.json"
2120
future_state_path: "integration_tests/future_state.json"
2221
full_refresh:
2322
- config_path: "secrets/config.json"
24-
configured_catalog_path: "integration_tests/configured_catalog.json"
25-
# Ad Insights API has estimated metrics in response, which is calculated based on another metrics.
26-
# Sometimes API doesn't return estimated metrics. E.g, cost_per_estimated_ad_recallers is calculated
27-
# as total amount spent divided by estimated ad recall lift rate. When second metric is equal to zero
28-
# API may or may not return value. Such behavior causes sequential reads test failing.
29-
# Because one read response contains this metric, and other doesn't.
30-
# Therefore, it's needed to ignore fields like this in API responses.
31-
ignored_fields:
32-
"ads_insights_age_and_gender": ["cost_per_estimated_ad_recallers"]
33-
"ad_creatives": ["thumbnail_url"]
34-
"ad_account": ["age"]
35-
"images": ["permalink_url"]

airbyte-integrations/connectors/source-facebook-marketing/integration_tests/configured_catalog.json

+9-41
Original file line numberDiff line numberDiff line change
@@ -34,61 +34,29 @@
3434
"stream": {
3535
"name": "ads_insights",
3636
"json_schema": {},
37-
"supported_sync_modes": ["full_refresh", "incremental"],
38-
"source_defined_cursor": true,
3937
"default_cursor_field": ["date_start"],
40-
"source_defined_primary_key": null,
41-
"namespace": null
42-
},
43-
"sync_mode": "incremental",
44-
"cursor_field": ["date_start"],
45-
"destination_sync_mode": "append",
46-
"primary_key": null
47-
},
48-
{
49-
"stream": {
50-
"name": "ads_insights_age_and_gender",
51-
"json_schema": {},
5238
"supported_sync_modes": ["full_refresh", "incremental"],
5339
"source_defined_cursor": true,
54-
"default_cursor_field": ["date_start"],
55-
"source_defined_primary_key": null,
56-
"namespace": null
40+
"source_defined_primary_key": []
5741
},
5842
"sync_mode": "incremental",
43+
"primary_key": [],
5944
"cursor_field": ["date_start"],
60-
"destination_sync_mode": "append",
61-
"primary_key": null
45+
"destination_sync_mode": "append"
6246
},
6347
{
6448
"stream": {
65-
"name": "images",
49+
"name": "ads_insights_platform_and_device",
6650
"json_schema": {},
51+
"default_cursor_field": ["date_start"],
6752
"supported_sync_modes": ["full_refresh", "incremental"],
6853
"source_defined_cursor": true,
69-
"default_cursor_field": ["updated_time"],
70-
"source_defined_primary_key": [["id"]],
71-
"namespace": null
54+
"source_defined_primary_key": []
7255
},
7356
"sync_mode": "incremental",
74-
"cursor_field": null,
75-
"destination_sync_mode": "append",
76-
"primary_key": null
77-
},
78-
{
79-
"stream": {
80-
"name": "ad_account",
81-
"json_schema": {},
82-
"supported_sync_modes": ["full_refresh"],
83-
"source_defined_cursor": null,
84-
"default_cursor_field": null,
85-
"source_defined_primary_key": [["id"]],
86-
"namespace": null
87-
},
88-
"sync_mode": "full_refresh",
89-
"cursor_field": null,
90-
"destination_sync_mode": "append",
91-
"primary_key": null
57+
"primary_key": [],
58+
"cursor_field": ["date_start"],
59+
"destination_sync_mode": "append"
9260
}
9361
]
9462
}

airbyte-integrations/connectors/source-facebook-marketing/integration_tests/configured_catalog_without_insights.json

+4-8
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,7 @@
77
"supported_sync_modes": ["full_refresh", "incremental"],
88
"source_defined_cursor": true,
99
"default_cursor_field": ["updated_time"],
10-
"source_defined_primary_key": [["id"]],
11-
"namespace": null
10+
"source_defined_primary_key": [["id"]]
1211
},
1312
"sync_mode": "incremental",
1413
"cursor_field": null,
@@ -22,13 +21,11 @@
2221
"supported_sync_modes": ["full_refresh", "incremental"],
2322
"source_defined_cursor": true,
2423
"default_cursor_field": ["updated_time"],
25-
"source_defined_primary_key": [["id"]],
26-
"namespace": null
24+
"source_defined_primary_key": [["id"]]
2725
},
2826
"sync_mode": "incremental",
2927
"cursor_field": null,
30-
"destination_sync_mode": "append",
31-
"primary_key": null
28+
"destination_sync_mode": "append"
3229
},
3330
{
3431
"stream": {
@@ -37,8 +34,7 @@
3734
"supported_sync_modes": ["full_refresh", "incremental"],
3835
"source_defined_cursor": true,
3936
"default_cursor_field": ["updated_time"],
40-
"source_defined_primary_key": [["id"]],
41-
"namespace": null
37+
"source_defined_primary_key": [["id"]]
4238
},
4339
"sync_mode": "incremental",
4440
"cursor_field": null,

airbyte-integrations/connectors/source-facebook-marketing/integration_tests/conftest.py

+4-1
Original file line numberDiff line numberDiff line change
@@ -26,4 +26,7 @@ def config_with_wrong_account_fixture(config):
2626

2727
@pytest.fixture(scope="session", name="config_with_include_deleted")
2828
def config_with_include_deleted_fixture(config):
29-
return {**config, "include_deleted": True}
29+
new_config = {**config, "include_deleted": True}
30+
new_config.pop("_limit", None)
31+
new_config.pop("end_date", None)
32+
return new_config

0 commit comments

Comments
 (0)