atlan-application-sdk 0.1.1rc55__py3-none-any.whl → 0.1.1rc57__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.
@@ -256,7 +256,7 @@ REDIS_SENTINEL_HOSTS = os.getenv("REDIS_SENTINEL_HOSTS", "")
256
256
  #: Whether to enable strict locking
257
257
  IS_LOCKING_DISABLED = os.getenv("IS_LOCKING_DISABLED", "true").lower() == "true"
258
258
  #: Retry interval for lock acquisition
259
- LOCK_RETRY_INTERVAL = int(os.getenv("LOCK_RETRY_INTERVAL", "5"))
259
+ LOCK_RETRY_INTERVAL_SECONDS = int(os.getenv("LOCK_RETRY_INTERVAL_SECONDS", "60"))
260
260
 
261
261
  # MCP Configuration
262
262
  #: Flag to indicate if MCP should be enabled or not. Turning this to true will setup an MCP server along
@@ -2,6 +2,11 @@
2
2
 
3
3
  Manages distributed locks for activities decorated with @needs_lock using
4
4
  separate lock acquisition and release activities to avoid workflow deadlocks.
5
+
6
+ IMPORTANT: Uses regular activities (not local activities) for lock operations to prevent
7
+ workflow task blocking and deadlocks. Local activities would block the workflow task during
8
+ lock acquisition retries, preventing lock releases from executing and causing infinite deadlock
9
+ when all lock slots are taken.
5
10
  """
6
11
 
7
12
  from datetime import timedelta
@@ -22,7 +27,7 @@ from application_sdk.constants import (
22
27
  APPLICATION_NAME,
23
28
  IS_LOCKING_DISABLED,
24
29
  LOCK_METADATA_KEY,
25
- LOCK_RETRY_INTERVAL,
30
+ LOCK_RETRY_INTERVAL_SECONDS,
26
31
  )
27
32
  from application_sdk.observability.logger_adaptor import get_logger
28
33
 
@@ -109,12 +114,14 @@ class RedisLockOutboundInterceptor(WorkflowOutboundInterceptor):
109
114
  try:
110
115
  # Step 1: Acquire lock via dedicated activity with Temporal retry policy
111
116
  schedule_to_close_timeout = workflow.info().execution_timeout
112
- lock_result = await workflow.execute_local_activity(
117
+ lock_result = await workflow.execute_activity(
113
118
  "acquire_distributed_lock",
114
119
  args=[lock_name, max_locks, ttl_seconds, owner_id],
115
120
  start_to_close_timeout=timedelta(seconds=30),
116
121
  retry_policy=RetryPolicy(
117
- initial_interval=timedelta(seconds=int(LOCK_RETRY_INTERVAL)),
122
+ initial_interval=timedelta(
123
+ seconds=int(LOCK_RETRY_INTERVAL_SECONDS)
124
+ ),
118
125
  backoff_coefficient=1.0,
119
126
  ),
120
127
  schedule_to_close_timeout=schedule_to_close_timeout,
@@ -129,7 +136,7 @@ class RedisLockOutboundInterceptor(WorkflowOutboundInterceptor):
129
136
  # Step 3: Release lock (fire-and-forget with short timeout)
130
137
  if lock_result is not None:
131
138
  try:
132
- await workflow.execute_local_activity(
139
+ await workflow.execute_activity(
133
140
  "release_distributed_lock",
134
141
  args=[lock_result["resource_id"], lock_result["owner_id"]],
135
142
  start_to_close_timeout=timedelta(seconds=5),
@@ -211,14 +211,20 @@ for logger_name in DEPENDENCY_LOGGERS:
211
211
 
212
212
  # Add these constants
213
213
  SEVERITY_MAPPING = {
214
- "DEBUG": SeverityNumber.DEBUG,
215
- "INFO": SeverityNumber.INFO,
216
- "WARNING": SeverityNumber.WARN,
217
- "ERROR": SeverityNumber.ERROR,
218
- "CRITICAL": SeverityNumber.FATAL,
219
- "ACTIVITY": SeverityNumber.INFO, # Using INFO severity for activity level
220
- "METRIC": SeverityNumber.INFO, # Using INFO severity for metric level
221
- "TRACING": SeverityNumber.INFO, # Using INFO severity for tracing level
214
+ "DEBUG": logging.getLevelNamesMapping()["DEBUG"],
215
+ "INFO": logging.getLevelNamesMapping()["INFO"],
216
+ "WARNING": logging.getLevelNamesMapping()["WARNING"],
217
+ "ERROR": logging.getLevelNamesMapping()["ERROR"],
218
+ "CRITICAL": logging.getLevelNamesMapping()["CRITICAL"],
219
+ "ACTIVITY": logging.getLevelNamesMapping()[
220
+ "INFO"
221
+ ], # Using INFO severity for activity level
222
+ "METRIC": logging.getLevelNamesMapping()[
223
+ "DEBUG"
224
+ ], # Using DEBUG severity for metric level
225
+ "TRACING": logging.getLevelNamesMapping()[
226
+ "DEBUG"
227
+ ], # Using DEBUG severity for tracing level
222
228
  }
223
229
 
224
230
 
@@ -264,25 +270,34 @@ class AtlanLoggerAdapter(AtlanObservability[LogRecordModel]):
264
270
 
265
271
  # Register custom log level for activity
266
272
  if "ACTIVITY" not in logger._core.levels:
267
- logger.level("ACTIVITY", no=20, color="<cyan>", icon="🔵")
273
+ logger.level(
274
+ "ACTIVITY", no=SEVERITY_MAPPING["ACTIVITY"], color="<cyan>", icon="🔵"
275
+ )
268
276
 
269
277
  # Register custom log level for metrics
270
278
  if "METRIC" not in logger._core.levels:
271
- logger.level("METRIC", no=20, color="<yellow>", icon="📊")
279
+ logger.level(
280
+ "METRIC", no=SEVERITY_MAPPING["METRIC"], color="<yellow>", icon="📊"
281
+ )
272
282
 
273
283
  # Register custom log level for tracing
274
284
  if "TRACING" not in logger._core.levels:
275
- logger.level("TRACING", no=20, color="<magenta>", icon="🔍")
285
+ logger.level(
286
+ "TRACING", no=SEVERITY_MAPPING["TRACING"], color="<magenta>", icon="🔍"
287
+ )
276
288
 
277
289
  # Update format string to use the bound logger_name
278
290
  atlan_format_str = "<green>{time:YYYY-MM-DD HH:mm:ss}</green> <blue>[{level}]</blue> <cyan>{extra[logger_name]}</cyan> - <level>{message}</level>"
279
291
  self.logger.add(
280
- sys.stderr, format=atlan_format_str, level=LOG_LEVEL, colorize=True
292
+ sys.stderr,
293
+ format=atlan_format_str,
294
+ level=SEVERITY_MAPPING[LOG_LEVEL],
295
+ colorize=True,
281
296
  )
282
297
 
283
298
  # Add sink for parquet logging only if Dapr sink is enabled
284
299
  if ENABLE_OBSERVABILITY_DAPR_SINK:
285
- self.logger.add(self.parquet_sink, level=LOG_LEVEL)
300
+ self.logger.add(self.parquet_sink, level=SEVERITY_MAPPING[LOG_LEVEL])
286
301
  # Start flush task only if Dapr sink is enabled
287
302
  if not AtlanLoggerAdapter._flush_task_started:
288
303
  try:
@@ -341,7 +356,7 @@ class AtlanLoggerAdapter(AtlanObservability[LogRecordModel]):
341
356
  self.logger_provider.add_log_record_processor(batch_processor)
342
357
 
343
358
  # Add OTLP sink
344
- self.logger.add(self.otlp_sink, level=LOG_LEVEL)
359
+ self.logger.add(self.otlp_sink, level=SEVERITY_MAPPING[LOG_LEVEL])
345
360
 
346
361
  except Exception as e:
347
362
  logging.error(f"Failed to setup OTLP logging: {str(e)}")
@@ -384,6 +384,7 @@ class AtlanMetricsAdapter(AtlanObservability[MetricRecord]):
384
384
  Raises:
385
385
  Exception: If logging fails, logs error and continues
386
386
  """
387
+
387
388
  try:
388
389
  log_message = (
389
390
  f"{metric_record.name} = {metric_record.value} "
@@ -2,4 +2,4 @@
2
2
  Version information for the application_sdk package.
3
3
  """
4
4
 
5
- __version__ = "0.1.1rc55"
5
+ __version__ = "0.1.1rc57"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: atlan-application-sdk
3
- Version: 0.1.1rc55
3
+ Version: 0.1.1rc57
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
@@ -62,6 +62,7 @@ Description-Content-Type: text/markdown
62
62
 
63
63
  # Atlan Application SDK
64
64
  [![On-Push Checks](https://github.com/atlanhq/application-sdk/actions/workflows/push.yaml/badge.svg)](https://github.com/atlanhq/application-sdk/actions/workflows/push.yaml) [![CodeQL Advanced](https://github.com/atlanhq/application-sdk/actions/workflows/codeql.yaml/badge.svg)](https://github.com/atlanhq/application-sdk/actions/workflows/codeql.yaml) [![PyPI version](https://img.shields.io/pypi/v/atlan-application-sdk.svg)](https://pypi.org/project/atlan-application-sdk/)
65
+ [![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/atlanhq/application-sdk)
65
66
 
66
67
  The Atlan Application SDK is a Python library designed for building applications on the Atlan platform. It offers a full PaaS (Platform-as-a-Service) toolkit — from local development to deployment and partner collaboration — so you can create integrations and tools that seamlessly extend the Atlan experience for our mutual customers.
67
68
 
@@ -1,6 +1,6 @@
1
1
  application_sdk/__init__.py,sha256=2e2mvmLJ5dxmJGPELtb33xwP-j6JMdoIuqKycEn7hjg,151
2
- application_sdk/constants.py,sha256=EDGR-3SuCxNV-3x0D4wA9is9vBbVWa3nHvJ8r2w4lYY,10977
3
- application_sdk/version.py,sha256=GSgUx92mCFDwTnAC5gx_IwXSMV4KwnJrIkRB3TCBNxQ,88
2
+ application_sdk/constants.py,sha256=WDw0I9u_OoXIE79IFDFBHJYmIS9KAsghMeGOxfshnpg,10994
3
+ application_sdk/version.py,sha256=IyB6vjth_E6FH7I1tBCb3R7pWpyympnG14_n5Dyzamc,88
4
4
  application_sdk/worker.py,sha256=i5f0AeKI39IfsLO05QkwC6uMz0zDPSJqP7B2byri1VI,7489
5
5
  application_sdk/activities/__init__.py,sha256=L5WXkTwOwGtjWAlXrUJRCKGwyIyp3z8fBv8BZVCRFQI,11175
6
6
  application_sdk/activities/lock_management.py,sha256=oX2qPpfEu_xP0MiaCakVGk9ivZDvG4EddVZag1DuHSE,3976
@@ -68,11 +68,11 @@ application_sdk/inputs/.cursor/BUGBOT.md,sha256=hwKGDbopv3NU0bpC_ElpAPDFcS59GWS3
68
68
  application_sdk/interceptors/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
69
69
  application_sdk/interceptors/cleanup.py,sha256=JlFcM_2Y5AIEfGTSNe0aoon7eoE68MIXI0rA3LHsSeY,5966
70
70
  application_sdk/interceptors/events.py,sha256=TeStWmBbc4v1-dm2DWeKYsUfUhJLR8CtTQhu3TWOZWM,6524
71
- application_sdk/interceptors/lock.py,sha256=K1e1p11OYDDTy5TFMHcKXAvY4H86yXgpAZiuncEyH2M,5810
71
+ application_sdk/interceptors/lock.py,sha256=5ETm20zrTaH2b9fepN4Ckp1tGJV-uINqDrno_5RW3aw,6169
72
72
  application_sdk/interceptors/.cursor/BUGBOT.md,sha256=pxmUF2c7dtaXAX8yAa1-LBa6FCrj_uw7aQcHrppjf1A,14570
73
73
  application_sdk/observability/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
74
- application_sdk/observability/logger_adaptor.py,sha256=WTqnNg78W2SRGOQVhELVLn6KMRsurkG1kc7essL08Lk,29529
75
- application_sdk/observability/metrics_adaptor.py,sha256=4TYPNn38zLeqxwf7cUbe8wh_zwQlr-nyiXjJsiEhTEM,16445
74
+ application_sdk/observability/logger_adaptor.py,sha256=00c0F7maDkp1xrHttW6VQbWFDGr6NkXeDPjmf97ojlY,29989
75
+ application_sdk/observability/metrics_adaptor.py,sha256=5Oz02lUED60duryoVDF9mbD11fpxhbXi7P1609n_15Y,16446
76
76
  application_sdk/observability/observability.py,sha256=DP0I4bHyg3TA4hxCqDFy2IiRmBGOpZ7449m7BUoc_RA,24530
77
77
  application_sdk/observability/traces_adaptor.py,sha256=0eQJPN-tYA_dV8D3uEa5ZiX9g12NDuLnPaFuQMVDdL0,18242
78
78
  application_sdk/observability/utils.py,sha256=MKEpT0WYtpATUgLgJDkGQaAP_t-jpDYMUKDfEvr8Phg,2448
@@ -157,8 +157,8 @@ application_sdk/workflows/metadata_extraction/__init__.py,sha256=jHUe_ZBQ66jx8bg
157
157
  application_sdk/workflows/metadata_extraction/sql.py,sha256=6ZaVt84n-8U2ZvR9GR7uIJKv5v8CuyQjhlnoRJvDszc,12435
158
158
  application_sdk/workflows/query_extraction/__init__.py,sha256=n066_CX5RpJz6DIxGMkKS3eGSRg03ilaCtsqfJWQb7Q,117
159
159
  application_sdk/workflows/query_extraction/sql.py,sha256=kT_JQkLCRZ44ZpaC4QvPL6DxnRIIVh8gYHLqRbMI-hA,4826
160
- atlan_application_sdk-0.1.1rc55.dist-info/METADATA,sha256=oPFC4krNFgKJYPm5q8u6Cji9hKoZfflnMTTGi8-c7SQ,5634
161
- atlan_application_sdk-0.1.1rc55.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
162
- atlan_application_sdk-0.1.1rc55.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
163
- atlan_application_sdk-0.1.1rc55.dist-info/licenses/NOTICE,sha256=A-XVVGt3KOYuuMmvSMIFkg534F1vHiCggEBp4Ez3wGk,1041
164
- atlan_application_sdk-0.1.1rc55.dist-info/RECORD,,
160
+ atlan_application_sdk-0.1.1rc57.dist-info/METADATA,sha256=x-HZpkwfS5eNSCyuJAvfy1-X1DznYqFVVdCBbDNmmyc,5730
161
+ atlan_application_sdk-0.1.1rc57.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
162
+ atlan_application_sdk-0.1.1rc57.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
163
+ atlan_application_sdk-0.1.1rc57.dist-info/licenses/NOTICE,sha256=A-XVVGt3KOYuuMmvSMIFkg534F1vHiCggEBp4Ez3wGk,1041
164
+ atlan_application_sdk-0.1.1rc57.dist-info/RECORD,,