port-ocean 0.4.9__tar.gz → 0.4.10__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.
Potentially problematic release.
This version of port-ocean might be problematic. Click here for more details.
- {port_ocean-0.4.9 → port_ocean-0.4.10}/PKG-INFO +1 -1
- {port_ocean-0.4.9 → port_ocean-0.4.10}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/Makefile +0 -1
- {port_ocean-0.4.9 → port_ocean-0.4.10}/port_ocean/clients/port/mixins/entities.py +93 -38
- {port_ocean-0.4.9 → port_ocean-0.4.10}/port_ocean/clients/port/retry_transport.py +2 -2
- {port_ocean-0.4.9 → port_ocean-0.4.10}/port_ocean/clients/port/utils.py +14 -14
- {port_ocean-0.4.9 → port_ocean-0.4.10}/port_ocean/core/handlers/entities_state_applier/port/applier.py +10 -21
- port_ocean-0.4.10/port_ocean/helpers/async_client.py +53 -0
- {port_ocean-0.4.9 → port_ocean-0.4.10}/port_ocean/utils.py +3 -7
- {port_ocean-0.4.9 → port_ocean-0.4.10}/pyproject.toml +1 -1
- {port_ocean-0.4.9 → port_ocean-0.4.10}/LICENSE.md +0 -0
- {port_ocean-0.4.9 → port_ocean-0.4.10}/README.md +0 -0
- {port_ocean-0.4.9 → port_ocean-0.4.10}/port_ocean/__init__.py +0 -0
- {port_ocean-0.4.9 → port_ocean-0.4.10}/port_ocean/bootstrap.py +0 -0
- {port_ocean-0.4.9 → port_ocean-0.4.10}/port_ocean/cli/__init__.py +0 -0
- {port_ocean-0.4.9 → port_ocean-0.4.10}/port_ocean/cli/cli.py +0 -0
- {port_ocean-0.4.9 → port_ocean-0.4.10}/port_ocean/cli/commands/__init__.py +0 -0
- {port_ocean-0.4.9 → port_ocean-0.4.10}/port_ocean/cli/commands/defaults/__init___.py +0 -0
- {port_ocean-0.4.9 → port_ocean-0.4.10}/port_ocean/cli/commands/defaults/clean.py +0 -0
- {port_ocean-0.4.9 → port_ocean-0.4.10}/port_ocean/cli/commands/defaults/dock.py +0 -0
- {port_ocean-0.4.9 → port_ocean-0.4.10}/port_ocean/cli/commands/defaults/group.py +0 -0
- {port_ocean-0.4.9 → port_ocean-0.4.10}/port_ocean/cli/commands/list_integrations.py +0 -0
- {port_ocean-0.4.9 → port_ocean-0.4.10}/port_ocean/cli/commands/main.py +0 -0
- {port_ocean-0.4.9 → port_ocean-0.4.10}/port_ocean/cli/commands/new.py +0 -0
- {port_ocean-0.4.9 → port_ocean-0.4.10}/port_ocean/cli/commands/pull.py +0 -0
- {port_ocean-0.4.9 → port_ocean-0.4.10}/port_ocean/cli/commands/sail.py +0 -0
- {port_ocean-0.4.9 → port_ocean-0.4.10}/port_ocean/cli/commands/version.py +0 -0
- {port_ocean-0.4.9 → port_ocean-0.4.10}/port_ocean/cli/cookiecutter/__init__.py +0 -0
- {port_ocean-0.4.9 → port_ocean-0.4.10}/port_ocean/cli/cookiecutter/cookiecutter.json +0 -0
- {port_ocean-0.4.9 → port_ocean-0.4.10}/port_ocean/cli/cookiecutter/extensions.py +0 -0
- {port_ocean-0.4.9 → port_ocean-0.4.10}/port_ocean/cli/cookiecutter/hooks/post_gen_project.py +0 -0
- {port_ocean-0.4.9 → port_ocean-0.4.10}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/.dockerignore +0 -0
- {port_ocean-0.4.9 → port_ocean-0.4.10}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/.gitignore +0 -0
- {port_ocean-0.4.9 → port_ocean-0.4.10}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/.port/resources/.gitignore +0 -0
- {port_ocean-0.4.9 → port_ocean-0.4.10}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/.port/spec.yaml +0 -0
- {port_ocean-0.4.9 → port_ocean-0.4.10}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/CHANGELOG.md +0 -0
- {port_ocean-0.4.9 → port_ocean-0.4.10}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/Dockerfile +0 -0
- {port_ocean-0.4.9 → port_ocean-0.4.10}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/README.md +0 -0
- {port_ocean-0.4.9 → port_ocean-0.4.10}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/changelog/.gitignore +0 -0
- {port_ocean-0.4.9 → port_ocean-0.4.10}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/config.yaml +0 -0
- {port_ocean-0.4.9 → port_ocean-0.4.10}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/debug.py +0 -0
- {port_ocean-0.4.9 → port_ocean-0.4.10}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/main.py +0 -0
- {port_ocean-0.4.9 → port_ocean-0.4.10}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/poetry.toml +0 -0
- {port_ocean-0.4.9 → port_ocean-0.4.10}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/pyproject.toml +0 -0
- {port_ocean-0.4.9 → port_ocean-0.4.10}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/tests/__init__.py +0 -0
- {port_ocean-0.4.9 → port_ocean-0.4.10}/port_ocean/cli/utils.py +0 -0
- {port_ocean-0.4.9 → port_ocean-0.4.10}/port_ocean/clients/__init__.py +0 -0
- {port_ocean-0.4.9 → port_ocean-0.4.10}/port_ocean/clients/port/__init__.py +0 -0
- {port_ocean-0.4.9 → port_ocean-0.4.10}/port_ocean/clients/port/authentication.py +0 -0
- {port_ocean-0.4.9 → port_ocean-0.4.10}/port_ocean/clients/port/client.py +0 -0
- {port_ocean-0.4.9 → port_ocean-0.4.10}/port_ocean/clients/port/mixins/__init__.py +0 -0
- {port_ocean-0.4.9 → port_ocean-0.4.10}/port_ocean/clients/port/mixins/blueprints.py +0 -0
- {port_ocean-0.4.9 → port_ocean-0.4.10}/port_ocean/clients/port/mixins/integrations.py +0 -0
- {port_ocean-0.4.9 → port_ocean-0.4.10}/port_ocean/clients/port/mixins/migrations.py +0 -0
- {port_ocean-0.4.9 → port_ocean-0.4.10}/port_ocean/clients/port/types.py +0 -0
- {port_ocean-0.4.9 → port_ocean-0.4.10}/port_ocean/config/__init__.py +0 -0
- {port_ocean-0.4.9 → port_ocean-0.4.10}/port_ocean/config/base.py +0 -0
- {port_ocean-0.4.9 → port_ocean-0.4.10}/port_ocean/config/dynamic.py +0 -0
- {port_ocean-0.4.9 → port_ocean-0.4.10}/port_ocean/config/settings.py +0 -0
- {port_ocean-0.4.9 → port_ocean-0.4.10}/port_ocean/consumers/__init__.py +0 -0
- {port_ocean-0.4.9 → port_ocean-0.4.10}/port_ocean/consumers/base_consumer.py +0 -0
- {port_ocean-0.4.9 → port_ocean-0.4.10}/port_ocean/consumers/kafka_consumer.py +0 -0
- {port_ocean-0.4.9 → port_ocean-0.4.10}/port_ocean/context/__init__.py +0 -0
- {port_ocean-0.4.9 → port_ocean-0.4.10}/port_ocean/context/event.py +0 -0
- {port_ocean-0.4.9 → port_ocean-0.4.10}/port_ocean/context/ocean.py +0 -0
- {port_ocean-0.4.9 → port_ocean-0.4.10}/port_ocean/context/resource.py +0 -0
- {port_ocean-0.4.9 → port_ocean-0.4.10}/port_ocean/context/utils.py +0 -0
- {port_ocean-0.4.9 → port_ocean-0.4.10}/port_ocean/core/__init__.py +0 -0
- {port_ocean-0.4.9 → port_ocean-0.4.10}/port_ocean/core/defaults/__init__.py +0 -0
- {port_ocean-0.4.9 → port_ocean-0.4.10}/port_ocean/core/defaults/clean.py +0 -0
- {port_ocean-0.4.9 → port_ocean-0.4.10}/port_ocean/core/defaults/common.py +0 -0
- {port_ocean-0.4.9 → port_ocean-0.4.10}/port_ocean/core/defaults/initialize.py +0 -0
- {port_ocean-0.4.9 → port_ocean-0.4.10}/port_ocean/core/event_listener/__init__.py +0 -0
- {port_ocean-0.4.9 → port_ocean-0.4.10}/port_ocean/core/event_listener/base.py +0 -0
- {port_ocean-0.4.9 → port_ocean-0.4.10}/port_ocean/core/event_listener/factory.py +0 -0
- {port_ocean-0.4.9 → port_ocean-0.4.10}/port_ocean/core/event_listener/http.py +0 -0
- {port_ocean-0.4.9 → port_ocean-0.4.10}/port_ocean/core/event_listener/kafka.py +0 -0
- {port_ocean-0.4.9 → port_ocean-0.4.10}/port_ocean/core/event_listener/once.py +0 -0
- {port_ocean-0.4.9 → port_ocean-0.4.10}/port_ocean/core/event_listener/polling.py +0 -0
- {port_ocean-0.4.9 → port_ocean-0.4.10}/port_ocean/core/handlers/__init__.py +0 -0
- {port_ocean-0.4.9 → port_ocean-0.4.10}/port_ocean/core/handlers/base.py +0 -0
- {port_ocean-0.4.9 → port_ocean-0.4.10}/port_ocean/core/handlers/entities_state_applier/__init__.py +0 -0
- {port_ocean-0.4.9 → port_ocean-0.4.10}/port_ocean/core/handlers/entities_state_applier/base.py +0 -0
- {port_ocean-0.4.9 → port_ocean-0.4.10}/port_ocean/core/handlers/entities_state_applier/port/__init__.py +0 -0
- {port_ocean-0.4.9 → port_ocean-0.4.10}/port_ocean/core/handlers/entities_state_applier/port/get_related_entities.py +0 -0
- {port_ocean-0.4.9 → port_ocean-0.4.10}/port_ocean/core/handlers/entities_state_applier/port/order_by_entities_dependencies.py +0 -0
- {port_ocean-0.4.9 → port_ocean-0.4.10}/port_ocean/core/handlers/entities_state_applier/port/validate_entity_relations.py +0 -0
- {port_ocean-0.4.9 → port_ocean-0.4.10}/port_ocean/core/handlers/entity_processor/__init__.py +0 -0
- {port_ocean-0.4.9 → port_ocean-0.4.10}/port_ocean/core/handlers/entity_processor/base.py +0 -0
- {port_ocean-0.4.9 → port_ocean-0.4.10}/port_ocean/core/handlers/entity_processor/jq_entity_processor.py +0 -0
- {port_ocean-0.4.9 → port_ocean-0.4.10}/port_ocean/core/handlers/port_app_config/__init__.py +0 -0
- {port_ocean-0.4.9 → port_ocean-0.4.10}/port_ocean/core/handlers/port_app_config/api.py +0 -0
- {port_ocean-0.4.9 → port_ocean-0.4.10}/port_ocean/core/handlers/port_app_config/base.py +0 -0
- {port_ocean-0.4.9 → port_ocean-0.4.10}/port_ocean/core/handlers/port_app_config/models.py +0 -0
- {port_ocean-0.4.9 → port_ocean-0.4.10}/port_ocean/core/integrations/__init__.py +0 -0
- {port_ocean-0.4.9 → port_ocean-0.4.10}/port_ocean/core/integrations/base.py +0 -0
- {port_ocean-0.4.9 → port_ocean-0.4.10}/port_ocean/core/integrations/mixins/__init__.py +0 -0
- {port_ocean-0.4.9 → port_ocean-0.4.10}/port_ocean/core/integrations/mixins/events.py +0 -0
- {port_ocean-0.4.9 → port_ocean-0.4.10}/port_ocean/core/integrations/mixins/handler.py +0 -0
- {port_ocean-0.4.9 → port_ocean-0.4.10}/port_ocean/core/integrations/mixins/sync.py +0 -0
- {port_ocean-0.4.9 → port_ocean-0.4.10}/port_ocean/core/integrations/mixins/sync_raw.py +0 -0
- {port_ocean-0.4.9 → port_ocean-0.4.10}/port_ocean/core/integrations/mixins/utils.py +0 -0
- {port_ocean-0.4.9 → port_ocean-0.4.10}/port_ocean/core/models.py +0 -0
- {port_ocean-0.4.9 → port_ocean-0.4.10}/port_ocean/core/ocean_types.py +0 -0
- {port_ocean-0.4.9 → port_ocean-0.4.10}/port_ocean/core/utils.py +0 -0
- {port_ocean-0.4.9 → port_ocean-0.4.10}/port_ocean/exceptions/__init__.py +0 -0
- {port_ocean-0.4.9 → port_ocean-0.4.10}/port_ocean/exceptions/api.py +0 -0
- {port_ocean-0.4.9 → port_ocean-0.4.10}/port_ocean/exceptions/base.py +0 -0
- {port_ocean-0.4.9 → port_ocean-0.4.10}/port_ocean/exceptions/clients.py +0 -0
- {port_ocean-0.4.9 → port_ocean-0.4.10}/port_ocean/exceptions/context.py +0 -0
- {port_ocean-0.4.9 → port_ocean-0.4.10}/port_ocean/exceptions/core.py +0 -0
- {port_ocean-0.4.9 → port_ocean-0.4.10}/port_ocean/exceptions/port_defaults.py +0 -0
- {port_ocean-0.4.9 → port_ocean-0.4.10}/port_ocean/helpers/__init__.py +0 -0
- {port_ocean-0.4.9 → port_ocean-0.4.10}/port_ocean/helpers/retry.py +0 -0
- {port_ocean-0.4.9 → port_ocean-0.4.10}/port_ocean/logger_setup.py +0 -0
- {port_ocean-0.4.9 → port_ocean-0.4.10}/port_ocean/middlewares.py +0 -0
- {port_ocean-0.4.9 → port_ocean-0.4.10}/port_ocean/ocean.py +0 -0
- {port_ocean-0.4.9 → port_ocean-0.4.10}/port_ocean/py.typed +0 -0
- {port_ocean-0.4.9 → port_ocean-0.4.10}/port_ocean/run.py +0 -0
- {port_ocean-0.4.9 → port_ocean-0.4.10}/port_ocean/version.py +0 -0
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import asyncio
|
|
1
2
|
from urllib.parse import quote_plus
|
|
2
3
|
|
|
3
4
|
import httpx
|
|
@@ -5,7 +6,10 @@ from loguru import logger
|
|
|
5
6
|
|
|
6
7
|
from port_ocean.clients.port.authentication import PortAuthentication
|
|
7
8
|
from port_ocean.clients.port.types import RequestOptions, UserAgentType
|
|
8
|
-
from port_ocean.clients.port.utils import
|
|
9
|
+
from port_ocean.clients.port.utils import (
|
|
10
|
+
handle_status_code,
|
|
11
|
+
PORT_HTTP_MAX_CONNECTIONS_LIMIT,
|
|
12
|
+
)
|
|
9
13
|
from port_ocean.core.models import Entity
|
|
10
14
|
|
|
11
15
|
|
|
@@ -13,6 +17,10 @@ class EntityClientMixin:
|
|
|
13
17
|
def __init__(self, auth: PortAuthentication, client: httpx.AsyncClient):
|
|
14
18
|
self.auth = auth
|
|
15
19
|
self.client = client
|
|
20
|
+
# Semaphore is used to limit the number of concurrent requests to port, to avoid overloading it.
|
|
21
|
+
# The number of concurrent requests is set to 90% of the max connections limit, to leave some room for other
|
|
22
|
+
# requests that are not related to entities.
|
|
23
|
+
self.semaphore = asyncio.Semaphore(round(0.9 * PORT_HTTP_MAX_CONNECTIONS_LIMIT))
|
|
16
24
|
|
|
17
25
|
async def upsert_entity(
|
|
18
26
|
self,
|
|
@@ -22,24 +30,24 @@ class EntityClientMixin:
|
|
|
22
30
|
should_raise: bool = True,
|
|
23
31
|
) -> None:
|
|
24
32
|
validation_only = request_options["validation_only"]
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
33
|
+
async with self.semaphore:
|
|
34
|
+
logger.info(
|
|
35
|
+
f"{'Validating' if validation_only else 'Upserting'} entity: {entity.identifier} of blueprint: {entity.blueprint}"
|
|
36
|
+
)
|
|
37
|
+
headers = await self.auth.headers(user_agent_type)
|
|
38
|
+
response = await self.client.post(
|
|
39
|
+
f"{self.auth.api_url}/blueprints/{entity.blueprint}/entities",
|
|
40
|
+
json=entity.dict(exclude_unset=True, by_alias=True),
|
|
41
|
+
headers=headers,
|
|
42
|
+
params={
|
|
43
|
+
"upsert": "true",
|
|
44
|
+
"merge": str(request_options["merge"]).lower(),
|
|
45
|
+
"create_missing_related_entities": str(
|
|
46
|
+
request_options["create_missing_related_entities"]
|
|
47
|
+
).lower(),
|
|
48
|
+
"validation_only": str(validation_only).lower(),
|
|
49
|
+
},
|
|
50
|
+
)
|
|
43
51
|
|
|
44
52
|
if response.is_error:
|
|
45
53
|
logger.error(
|
|
@@ -49,34 +57,81 @@ class EntityClientMixin:
|
|
|
49
57
|
)
|
|
50
58
|
handle_status_code(response, should_raise)
|
|
51
59
|
|
|
52
|
-
async def
|
|
60
|
+
async def batch_upsert_entities(
|
|
53
61
|
self,
|
|
54
|
-
|
|
62
|
+
entities: list[Entity],
|
|
55
63
|
request_options: RequestOptions,
|
|
56
64
|
user_agent_type: UserAgentType | None = None,
|
|
57
65
|
should_raise: bool = True,
|
|
58
66
|
) -> None:
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
67
|
+
await asyncio.gather(
|
|
68
|
+
*(
|
|
69
|
+
self.upsert_entity(
|
|
70
|
+
entity,
|
|
71
|
+
request_options,
|
|
72
|
+
user_agent_type,
|
|
73
|
+
should_raise=should_raise,
|
|
74
|
+
)
|
|
75
|
+
for entity in entities
|
|
76
|
+
),
|
|
77
|
+
return_exceptions=True,
|
|
70
78
|
)
|
|
71
79
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
80
|
+
async def delete_entity(
|
|
81
|
+
self,
|
|
82
|
+
entity: Entity,
|
|
83
|
+
request_options: RequestOptions,
|
|
84
|
+
user_agent_type: UserAgentType | None = None,
|
|
85
|
+
should_raise: bool = True,
|
|
86
|
+
) -> None:
|
|
87
|
+
async with self.semaphore:
|
|
88
|
+
logger.info(
|
|
89
|
+
f"Delete entity: {entity.identifier} of blueprint: {entity.blueprint}"
|
|
90
|
+
)
|
|
91
|
+
response = await self.client.delete(
|
|
92
|
+
f"{self.auth.api_url}/blueprints/{entity.blueprint}/entities/{quote_plus(entity.identifier)}",
|
|
93
|
+
headers=await self.auth.headers(user_agent_type),
|
|
94
|
+
params={
|
|
95
|
+
"delete_dependents": str(
|
|
96
|
+
request_options["delete_dependent_entities"]
|
|
97
|
+
).lower()
|
|
98
|
+
},
|
|
77
99
|
)
|
|
78
100
|
|
|
79
|
-
|
|
101
|
+
if response.is_error:
|
|
102
|
+
if response.status_code == 404:
|
|
103
|
+
logger.info(
|
|
104
|
+
f"Weren't able to delete entity: {entity.identifier} of blueprint: {entity.blueprint},"
|
|
105
|
+
f" as it was already deleted from port"
|
|
106
|
+
)
|
|
107
|
+
return
|
|
108
|
+
logger.error(
|
|
109
|
+
f"Error deleting "
|
|
110
|
+
f"entity: {entity.identifier} of "
|
|
111
|
+
f"blueprint: {entity.blueprint}"
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
handle_status_code(response, should_raise)
|
|
115
|
+
|
|
116
|
+
async def batch_delete_entities(
|
|
117
|
+
self,
|
|
118
|
+
entities: list[Entity],
|
|
119
|
+
request_options: RequestOptions,
|
|
120
|
+
user_agent_type: UserAgentType | None = None,
|
|
121
|
+
should_raise: bool = True,
|
|
122
|
+
) -> None:
|
|
123
|
+
await asyncio.gather(
|
|
124
|
+
*(
|
|
125
|
+
self.delete_entity(
|
|
126
|
+
entity,
|
|
127
|
+
request_options,
|
|
128
|
+
user_agent_type,
|
|
129
|
+
should_raise=should_raise,
|
|
130
|
+
)
|
|
131
|
+
for entity in entities
|
|
132
|
+
),
|
|
133
|
+
return_exceptions=True,
|
|
134
|
+
)
|
|
80
135
|
|
|
81
136
|
async def validate_entity_exist(self, identifier: str, blueprint: str) -> None:
|
|
82
137
|
logger.info(f"Validating entity {identifier} of blueprint {blueprint} exists")
|
|
@@ -11,8 +11,8 @@ if TYPE_CHECKING:
|
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
class TokenRetryTransport(RetryTransport):
|
|
14
|
-
def __init__(self, port_client: "PortClient",
|
|
15
|
-
super().__init__(
|
|
14
|
+
def __init__(self, port_client: "PortClient", **kwargs: Any) -> None:
|
|
15
|
+
super().__init__(**kwargs)
|
|
16
16
|
self.port_client = port_client
|
|
17
17
|
|
|
18
18
|
def _is_retryable_method(self, request: httpx.Request) -> bool:
|
|
@@ -5,13 +5,11 @@ from loguru import logger
|
|
|
5
5
|
from werkzeug.local import LocalStack, LocalProxy
|
|
6
6
|
|
|
7
7
|
from port_ocean.clients.port.retry_transport import TokenRetryTransport
|
|
8
|
+
from port_ocean.helpers.async_client import OceanAsyncClient
|
|
8
9
|
|
|
9
10
|
if TYPE_CHECKING:
|
|
10
11
|
from port_ocean.clients.port.client import PortClient
|
|
11
12
|
|
|
12
|
-
_http_client: LocalStack[httpx.AsyncClient] = LocalStack()
|
|
13
|
-
|
|
14
|
-
|
|
15
13
|
# In case the framework sends more requests to port in parallel then allowed by the limits, a PoolTimeout exception will
|
|
16
14
|
# be raised.
|
|
17
15
|
# Raising defaults for the timeout, in addition to the limits, will allow request to wait for a connection for a longer
|
|
@@ -19,23 +17,25 @@ _http_client: LocalStack[httpx.AsyncClient] = LocalStack()
|
|
|
19
17
|
# We don't want to set the max_connections too highly, as it will cause the application to run out of memory.
|
|
20
18
|
# We also don't want to set the max_keepalive_connections too highly, as it will cause the application to run out of
|
|
21
19
|
# available connections.
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
20
|
+
PORT_HTTP_MAX_CONNECTIONS_LIMIT = 200
|
|
21
|
+
PORT_HTTP_MAX_KEEP_ALIVE_CONNECTIONS = 50
|
|
22
|
+
PORT_HTTP_TIMEOUT = 10.0
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
_http_client: LocalStack[httpx.AsyncClient] = LocalStack()
|
|
26
26
|
|
|
27
27
|
|
|
28
28
|
def _get_http_client_context(port_client: "PortClient") -> httpx.AsyncClient:
|
|
29
29
|
client = _http_client.top
|
|
30
30
|
if client is None:
|
|
31
|
-
client =
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
31
|
+
client = OceanAsyncClient(
|
|
32
|
+
TokenRetryTransport,
|
|
33
|
+
transport_kwargs={"port_client": port_client},
|
|
34
|
+
timeout=httpx.Timeout(PORT_HTTP_TIMEOUT),
|
|
35
|
+
limits=httpx.Limits(
|
|
36
|
+
max_connections=PORT_HTTP_MAX_CONNECTIONS_LIMIT,
|
|
37
|
+
max_keepalive_connections=PORT_HTTP_MAX_KEEP_ALIVE_CONNECTIONS,
|
|
36
38
|
),
|
|
37
|
-
timeout=PORT_HTTP_CLIENT_TIMEOUT,
|
|
38
|
-
limits=PORT_HTTP_CLIENT_CONNECTIONS_LIMIT,
|
|
39
39
|
)
|
|
40
40
|
_http_client.push(client)
|
|
41
41
|
|
|
@@ -158,17 +158,11 @@ class HttpEntitiesStateApplier(BaseEntitiesStateApplier):
|
|
|
158
158
|
) -> None:
|
|
159
159
|
logger.info(f"Upserting {len(entities)} entities")
|
|
160
160
|
if event.port_app_config.create_missing_related_entities:
|
|
161
|
-
await
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
user_agent_type,
|
|
167
|
-
should_raise=False,
|
|
168
|
-
)
|
|
169
|
-
for entity in entities
|
|
170
|
-
),
|
|
171
|
-
return_exceptions=True,
|
|
161
|
+
await self.context.port_client.batch_upsert_entities(
|
|
162
|
+
entities,
|
|
163
|
+
event.port_app_config.get_port_request_options(),
|
|
164
|
+
user_agent_type,
|
|
165
|
+
should_raise=False,
|
|
172
166
|
)
|
|
173
167
|
else:
|
|
174
168
|
ordered_created_entities = reversed(
|
|
@@ -188,16 +182,11 @@ class HttpEntitiesStateApplier(BaseEntitiesStateApplier):
|
|
|
188
182
|
) -> None:
|
|
189
183
|
logger.info(f"Deleting {len(entities)} entities")
|
|
190
184
|
if event.port_app_config.delete_dependent_entities:
|
|
191
|
-
await
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
user_agent_type,
|
|
197
|
-
should_raise=False,
|
|
198
|
-
)
|
|
199
|
-
for entity in entities
|
|
200
|
-
)
|
|
185
|
+
await self.context.port_client.batch_delete_entities(
|
|
186
|
+
entities,
|
|
187
|
+
event.port_app_config.get_port_request_options(),
|
|
188
|
+
user_agent_type,
|
|
189
|
+
should_raise=False,
|
|
201
190
|
)
|
|
202
191
|
else:
|
|
203
192
|
ordered_deleted_entities = order_by_entities_dependencies(entities)
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
from typing import Any, Callable, Type
|
|
2
|
+
|
|
3
|
+
import httpx
|
|
4
|
+
from loguru import logger
|
|
5
|
+
|
|
6
|
+
from port_ocean.helpers.retry import RetryTransport
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class OceanAsyncClient(httpx.AsyncClient):
|
|
10
|
+
"""
|
|
11
|
+
This class is a wrapper around httpx.AsyncClient that uses a custom transport class.
|
|
12
|
+
This is done to allow passing our custom transport class to the AsyncClient constructor while still allowing
|
|
13
|
+
all the default AsyncClient behavior that is changed when passing a custom transport instance.
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
def __init__(
|
|
17
|
+
self,
|
|
18
|
+
transport_class: Type[RetryTransport] = RetryTransport,
|
|
19
|
+
transport_kwargs: dict[str, Any] | None = None,
|
|
20
|
+
**kwargs: Any,
|
|
21
|
+
):
|
|
22
|
+
self._transport_kwargs = transport_kwargs
|
|
23
|
+
self._transport_class = transport_class
|
|
24
|
+
super().__init__(**kwargs)
|
|
25
|
+
|
|
26
|
+
def _init_transport( # type: ignore[override]
|
|
27
|
+
self,
|
|
28
|
+
transport: httpx.AsyncBaseTransport | None = None,
|
|
29
|
+
app: Callable[..., Any] | None = None,
|
|
30
|
+
**kwargs: Any,
|
|
31
|
+
) -> httpx.AsyncBaseTransport:
|
|
32
|
+
if transport is not None or app is not None:
|
|
33
|
+
return super()._init_transport(transport=transport, app=app, **kwargs)
|
|
34
|
+
|
|
35
|
+
return self._transport_class(
|
|
36
|
+
wrapped_transport=httpx.AsyncHTTPTransport(
|
|
37
|
+
**kwargs,
|
|
38
|
+
),
|
|
39
|
+
logger=logger,
|
|
40
|
+
**(self._transport_kwargs or {}),
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
def _init_proxy_transport( # type: ignore[override]
|
|
44
|
+
self, proxy: httpx.Proxy, **kwargs: Any
|
|
45
|
+
) -> httpx.AsyncBaseTransport:
|
|
46
|
+
return self._transport_class(
|
|
47
|
+
wrapped_transport=httpx.AsyncHTTPTransport(
|
|
48
|
+
proxy=proxy,
|
|
49
|
+
**kwargs,
|
|
50
|
+
),
|
|
51
|
+
logger=logger,
|
|
52
|
+
**(self._transport_kwargs or {}),
|
|
53
|
+
)
|
|
@@ -3,6 +3,7 @@ import inspect
|
|
|
3
3
|
from asyncio import ensure_future
|
|
4
4
|
from functools import wraps
|
|
5
5
|
from importlib.util import module_from_spec, spec_from_file_location
|
|
6
|
+
from pathlib import Path
|
|
6
7
|
from time import time
|
|
7
8
|
from traceback import format_exception
|
|
8
9
|
from types import ModuleType
|
|
@@ -13,10 +14,10 @@ import httpx
|
|
|
13
14
|
import tomli
|
|
14
15
|
import yaml
|
|
15
16
|
from loguru import logger
|
|
16
|
-
from pathlib import Path
|
|
17
17
|
from starlette.concurrency import run_in_threadpool
|
|
18
18
|
from werkzeug.local import LocalStack, LocalProxy
|
|
19
19
|
|
|
20
|
+
from port_ocean.helpers.async_client import OceanAsyncClient
|
|
20
21
|
from port_ocean.helpers.retry import RetryTransport
|
|
21
22
|
|
|
22
23
|
_http_client: LocalStack[httpx.AsyncClient] = LocalStack()
|
|
@@ -25,12 +26,7 @@ _http_client: LocalStack[httpx.AsyncClient] = LocalStack()
|
|
|
25
26
|
def _get_http_client_context() -> httpx.AsyncClient:
|
|
26
27
|
client = _http_client.top
|
|
27
28
|
if client is None:
|
|
28
|
-
client =
|
|
29
|
-
transport=RetryTransport(
|
|
30
|
-
httpx.AsyncHTTPTransport(),
|
|
31
|
-
logger=logger,
|
|
32
|
-
)
|
|
33
|
-
)
|
|
29
|
+
client = OceanAsyncClient(RetryTransport)
|
|
34
30
|
_http_client.push(client)
|
|
35
31
|
|
|
36
32
|
return client
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{port_ocean-0.4.9 → port_ocean-0.4.10}/port_ocean/cli/cookiecutter/hooks/post_gen_project.py
RENAMED
|
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
|
|
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
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{port_ocean-0.4.9 → port_ocean-0.4.10}/port_ocean/core/handlers/entities_state_applier/__init__.py
RENAMED
|
File without changes
|
{port_ocean-0.4.9 → port_ocean-0.4.10}/port_ocean/core/handlers/entities_state_applier/base.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{port_ocean-0.4.9 → port_ocean-0.4.10}/port_ocean/core/handlers/entity_processor/__init__.py
RENAMED
|
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
|
|
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
|
|
File without changes
|