atlan-application-sdk 0.1.1rc45__py3-none-any.whl → 0.1.1rc46__py3-none-any.whl
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.
- application_sdk/activities/lock_management.py +43 -42
- application_sdk/interceptors/lock.py +10 -5
- application_sdk/version.py +1 -1
- {atlan_application_sdk-0.1.1rc45.dist-info → atlan_application_sdk-0.1.1rc46.dist-info}/METADATA +1 -1
- {atlan_application_sdk-0.1.1rc45.dist-info → atlan_application_sdk-0.1.1rc46.dist-info}/RECORD +8 -8
- {atlan_application_sdk-0.1.1rc45.dist-info → atlan_application_sdk-0.1.1rc46.dist-info}/WHEEL +0 -0
- {atlan_application_sdk-0.1.1rc45.dist-info → atlan_application_sdk-0.1.1rc46.dist-info}/licenses/LICENSE +0 -0
- {atlan_application_sdk-0.1.1rc45.dist-info → atlan_application_sdk-0.1.1rc46.dist-info}/licenses/NOTICE +0 -0
|
@@ -5,15 +5,15 @@ allowing the workflow to orchestrate locking without hitting Temporal's
|
|
|
5
5
|
deadlock timeout.
|
|
6
6
|
"""
|
|
7
7
|
|
|
8
|
-
import asyncio
|
|
9
8
|
import random
|
|
10
9
|
from typing import Any, Dict
|
|
11
10
|
|
|
12
11
|
from temporalio import activity
|
|
12
|
+
from temporalio.exceptions import ApplicationError
|
|
13
13
|
|
|
14
14
|
from application_sdk.clients.redis import RedisClientAsync
|
|
15
15
|
from application_sdk.common.error_codes import ActivityError
|
|
16
|
-
from application_sdk.constants import APPLICATION_NAME
|
|
16
|
+
from application_sdk.constants import APPLICATION_NAME
|
|
17
17
|
from application_sdk.observability.logger_adaptor import get_logger
|
|
18
18
|
|
|
19
19
|
logger = get_logger(__name__)
|
|
@@ -45,40 +45,41 @@ async def acquire_distributed_lock(
|
|
|
45
45
|
"""
|
|
46
46
|
# Input validation
|
|
47
47
|
if max_locks <= 0:
|
|
48
|
-
raise
|
|
49
|
-
f"{ActivityError.LOCK_ACQUISITION_ERROR}: max_locks must be greater than 0, got {max_locks}"
|
|
48
|
+
raise ApplicationError(
|
|
49
|
+
f"{ActivityError.LOCK_ACQUISITION_ERROR}: max_locks must be greater than 0, got {max_locks}",
|
|
50
|
+
non_retryable=True,
|
|
51
|
+
)
|
|
52
|
+
slot = random.randint(0, max_locks - 1)
|
|
53
|
+
resource_id = f"{APPLICATION_NAME}:{lock_name}:{slot}"
|
|
54
|
+
|
|
55
|
+
try:
|
|
56
|
+
async with RedisClientAsync() as redis_client:
|
|
57
|
+
# Acquire lock - connection will stay open until context exits
|
|
58
|
+
acquired = await redis_client._acquire_lock(
|
|
59
|
+
resource_id, owner_id, ttl_seconds
|
|
60
|
+
)
|
|
61
|
+
if acquired:
|
|
62
|
+
logger.info(f"Lock acquired for slot {slot}, resource: {resource_id}")
|
|
63
|
+
return {
|
|
64
|
+
"status": True,
|
|
65
|
+
"slot_id": slot,
|
|
66
|
+
"resource_id": resource_id,
|
|
67
|
+
"owner_id": owner_id,
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
raise ActivityError(
|
|
71
|
+
f"{ActivityError.LOCK_ACQUISITION_ERROR}: Lock not acquired for {resource_id}, will retry after some time"
|
|
72
|
+
)
|
|
73
|
+
except Exception as e:
|
|
74
|
+
# Redis connection or operation failed - propagate as activity error
|
|
75
|
+
if isinstance(e, (ActivityError)):
|
|
76
|
+
raise e
|
|
77
|
+
logger.error(f"Redis error during lock acquisition: {e}")
|
|
78
|
+
raise ApplicationError(
|
|
79
|
+
f"Redis error during lock acquisition for {resource_id}, error: {e}",
|
|
80
|
+
non_retryable=True,
|
|
81
|
+
type=type(e).__name__,
|
|
50
82
|
)
|
|
51
|
-
|
|
52
|
-
async with RedisClientAsync() as redis_client:
|
|
53
|
-
while True:
|
|
54
|
-
slot = random.randint(0, max_locks - 1)
|
|
55
|
-
resource_id = f"{APPLICATION_NAME}:{lock_name}:{slot}"
|
|
56
|
-
|
|
57
|
-
try:
|
|
58
|
-
# Acquire lock - connection will stay open until context exits
|
|
59
|
-
acquired = await redis_client._acquire_lock(
|
|
60
|
-
resource_id, owner_id, ttl_seconds
|
|
61
|
-
)
|
|
62
|
-
if acquired:
|
|
63
|
-
logger.info(
|
|
64
|
-
f"Lock acquired for slot {slot}, resource: {resource_id}"
|
|
65
|
-
)
|
|
66
|
-
return {
|
|
67
|
-
"slot_id": slot,
|
|
68
|
-
"resource_id": resource_id,
|
|
69
|
-
"owner_id": owner_id,
|
|
70
|
-
}
|
|
71
|
-
# If not acquired, continue retrying (lock held by another owner)
|
|
72
|
-
|
|
73
|
-
except Exception as e:
|
|
74
|
-
# Redis connection or operation failed - propagate as activity error
|
|
75
|
-
logger.error(f"Redis error during lock acquisition: {e}")
|
|
76
|
-
raise ActivityError(
|
|
77
|
-
f"{ActivityError.LOCK_ACQUISITION_ERROR}: Redis error during lock acquisition for {resource_id}"
|
|
78
|
-
)
|
|
79
|
-
|
|
80
|
-
# Wait before retrying
|
|
81
|
-
await asyncio.sleep(LOCK_RETRY_INTERVAL)
|
|
82
83
|
|
|
83
84
|
|
|
84
85
|
@activity.defn
|
|
@@ -94,8 +95,8 @@ async def release_distributed_lock(
|
|
|
94
95
|
Returns:
|
|
95
96
|
True if lock was released successfully, False otherwise
|
|
96
97
|
"""
|
|
97
|
-
|
|
98
|
-
|
|
98
|
+
try:
|
|
99
|
+
async with RedisClientAsync() as redis_client:
|
|
99
100
|
released, result = await redis_client._release_lock(resource_id, owner_id)
|
|
100
101
|
if released:
|
|
101
102
|
logger.info(
|
|
@@ -103,8 +104,8 @@ async def release_distributed_lock(
|
|
|
103
104
|
)
|
|
104
105
|
return released
|
|
105
106
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
107
|
+
except Exception as e:
|
|
108
|
+
logger.error(f"Redis error during lock release for {resource_id}: {e}")
|
|
109
|
+
# Don't raise exception for lock release failures - log and return False
|
|
110
|
+
# Lock release is best-effort and shouldn't fail the workflow
|
|
111
|
+
return False
|
|
@@ -22,6 +22,7 @@ from application_sdk.constants import (
|
|
|
22
22
|
APPLICATION_NAME,
|
|
23
23
|
IS_LOCKING_DISABLED,
|
|
24
24
|
LOCK_METADATA_KEY,
|
|
25
|
+
LOCK_RETRY_INTERVAL,
|
|
25
26
|
)
|
|
26
27
|
from application_sdk.observability.logger_adaptor import get_logger
|
|
27
28
|
|
|
@@ -106,13 +107,17 @@ class RedisLockOutboundInterceptor(WorkflowOutboundInterceptor):
|
|
|
106
107
|
lock_result = None
|
|
107
108
|
|
|
108
109
|
try:
|
|
109
|
-
# Step 1: Acquire lock via dedicated activity
|
|
110
|
-
|
|
111
|
-
lock_result = await workflow.
|
|
110
|
+
# Step 1: Acquire lock via dedicated activity with Temporal retry policy
|
|
111
|
+
schedule_to_close_timeout = workflow.info().execution_timeout
|
|
112
|
+
lock_result = await workflow.execute_local_activity(
|
|
112
113
|
"acquire_distributed_lock",
|
|
113
114
|
args=[lock_name, max_locks, ttl_seconds, owner_id],
|
|
114
|
-
start_to_close_timeout=
|
|
115
|
-
retry_policy=RetryPolicy(
|
|
115
|
+
start_to_close_timeout=timedelta(seconds=30),
|
|
116
|
+
retry_policy=RetryPolicy(
|
|
117
|
+
initial_interval=timedelta(seconds=int(LOCK_RETRY_INTERVAL)),
|
|
118
|
+
backoff_coefficient=1.0,
|
|
119
|
+
),
|
|
120
|
+
schedule_to_close_timeout=schedule_to_close_timeout,
|
|
116
121
|
)
|
|
117
122
|
|
|
118
123
|
logger.debug(f"Lock acquired: {lock_result}, executing {input.activity}")
|
application_sdk/version.py
CHANGED
{atlan_application_sdk-0.1.1rc45.dist-info → atlan_application_sdk-0.1.1rc46.dist-info}/METADATA
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: atlan-application-sdk
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.1rc46
|
|
4
4
|
Summary: Atlan Application SDK is a Python library for developing applications on the Atlan Platform
|
|
5
5
|
Project-URL: Repository, https://github.com/atlanhq/application-sdk
|
|
6
6
|
Project-URL: Documentation, https://github.com/atlanhq/application-sdk/README.md
|
{atlan_application_sdk-0.1.1rc45.dist-info → atlan_application_sdk-0.1.1rc46.dist-info}/RECORD
RENAMED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
application_sdk/__init__.py,sha256=2e2mvmLJ5dxmJGPELtb33xwP-j6JMdoIuqKycEn7hjg,151
|
|
2
2
|
application_sdk/constants.py,sha256=eLHmH9GukXCKK-u5a4bAqz8BeCOCusCM0eW0Q0Bwjns,10947
|
|
3
|
-
application_sdk/version.py,sha256=
|
|
3
|
+
application_sdk/version.py,sha256=TTHbof7z1rqMmnKkkw-wrzn3nRqtDcXfc_kbnHfnflc,88
|
|
4
4
|
application_sdk/worker.py,sha256=i5f0AeKI39IfsLO05QkwC6uMz0zDPSJqP7B2byri1VI,7489
|
|
5
5
|
application_sdk/activities/__init__.py,sha256=QaXLOBYbb0zPOY5kfDQh56qbXQFaYNXOjJ5PCvatiZ4,9530
|
|
6
|
-
application_sdk/activities/lock_management.py,sha256=
|
|
6
|
+
application_sdk/activities/lock_management.py,sha256=oX2qPpfEu_xP0MiaCakVGk9ivZDvG4EddVZag1DuHSE,3976
|
|
7
7
|
application_sdk/activities/.cursor/BUGBOT.md,sha256=FNykX5aMkdOhzgpiGqstOnSp9JN63iR2XP3onU4AGh8,15843
|
|
8
8
|
application_sdk/activities/common/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
9
9
|
application_sdk/activities/common/models.py,sha256=LIZfWvTtgtbAUvvn-rwrPQgD7fP2J0Gxdxr_ITgw-jM,1243
|
|
@@ -67,7 +67,7 @@ application_sdk/inputs/.cursor/BUGBOT.md,sha256=hwKGDbopv3NU0bpC_ElpAPDFcS59GWS3
|
|
|
67
67
|
application_sdk/interceptors/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
68
68
|
application_sdk/interceptors/cleanup.py,sha256=JlFcM_2Y5AIEfGTSNe0aoon7eoE68MIXI0rA3LHsSeY,5966
|
|
69
69
|
application_sdk/interceptors/events.py,sha256=TeStWmBbc4v1-dm2DWeKYsUfUhJLR8CtTQhu3TWOZWM,6524
|
|
70
|
-
application_sdk/interceptors/lock.py,sha256=
|
|
70
|
+
application_sdk/interceptors/lock.py,sha256=K1e1p11OYDDTy5TFMHcKXAvY4H86yXgpAZiuncEyH2M,5810
|
|
71
71
|
application_sdk/interceptors/.cursor/BUGBOT.md,sha256=pxmUF2c7dtaXAX8yAa1-LBa6FCrj_uw7aQcHrppjf1A,14570
|
|
72
72
|
application_sdk/observability/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
73
73
|
application_sdk/observability/logger_adaptor.py,sha256=WTqnNg78W2SRGOQVhELVLn6KMRsurkG1kc7essL08Lk,29529
|
|
@@ -156,8 +156,8 @@ application_sdk/workflows/metadata_extraction/__init__.py,sha256=jHUe_ZBQ66jx8bg
|
|
|
156
156
|
application_sdk/workflows/metadata_extraction/sql.py,sha256=6ZaVt84n-8U2ZvR9GR7uIJKv5v8CuyQjhlnoRJvDszc,12435
|
|
157
157
|
application_sdk/workflows/query_extraction/__init__.py,sha256=n066_CX5RpJz6DIxGMkKS3eGSRg03ilaCtsqfJWQb7Q,117
|
|
158
158
|
application_sdk/workflows/query_extraction/sql.py,sha256=kT_JQkLCRZ44ZpaC4QvPL6DxnRIIVh8gYHLqRbMI-hA,4826
|
|
159
|
-
atlan_application_sdk-0.1.
|
|
160
|
-
atlan_application_sdk-0.1.
|
|
161
|
-
atlan_application_sdk-0.1.
|
|
162
|
-
atlan_application_sdk-0.1.
|
|
163
|
-
atlan_application_sdk-0.1.
|
|
159
|
+
atlan_application_sdk-0.1.1rc46.dist-info/METADATA,sha256=lFNImf3iOTzlw4bxeegOBO1YNjNfQ3yhAFzluCASQNI,5567
|
|
160
|
+
atlan_application_sdk-0.1.1rc46.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
161
|
+
atlan_application_sdk-0.1.1rc46.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
162
|
+
atlan_application_sdk-0.1.1rc46.dist-info/licenses/NOTICE,sha256=A-XVVGt3KOYuuMmvSMIFkg534F1vHiCggEBp4Ez3wGk,1041
|
|
163
|
+
atlan_application_sdk-0.1.1rc46.dist-info/RECORD,,
|
{atlan_application_sdk-0.1.1rc45.dist-info → atlan_application_sdk-0.1.1rc46.dist-info}/WHEEL
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|