async-lambda-unstable 0.4.18__tar.gz → 0.5.2__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.
Files changed (37) hide show
  1. {async-lambda-unstable-0.4.18 → async-lambda-unstable-0.5.2}/PKG-INFO +1 -1
  2. {async-lambda-unstable-0.4.18 → async-lambda-unstable-0.5.2}/async_lambda/__init__.py +1 -1
  3. {async-lambda-unstable-0.4.18 → async-lambda-unstable-0.5.2}/async_lambda/client.py +8 -0
  4. {async-lambda-unstable-0.4.18 → async-lambda-unstable-0.5.2}/async_lambda/controller.py +136 -44
  5. async-lambda-unstable-0.5.2/async_lambda/env.py +81 -0
  6. {async-lambda-unstable-0.4.18 → async-lambda-unstable-0.5.2}/async_lambda/models/task.py +28 -1
  7. {async-lambda-unstable-0.4.18 → async-lambda-unstable-0.5.2}/async_lambda_unstable.egg-info/PKG-INFO +1 -1
  8. async-lambda-unstable-0.4.18/async_lambda/env.py +0 -37
  9. {async-lambda-unstable-0.4.18 → async-lambda-unstable-0.5.2}/README.md +0 -0
  10. {async-lambda-unstable-0.4.18 → async-lambda-unstable-0.5.2}/async_lambda/build_config.py +0 -0
  11. {async-lambda-unstable-0.4.18 → async-lambda-unstable-0.5.2}/async_lambda/cli.py +0 -0
  12. {async-lambda-unstable-0.4.18 → async-lambda-unstable-0.5.2}/async_lambda/config.py +0 -0
  13. {async-lambda-unstable-0.4.18 → async-lambda-unstable-0.5.2}/async_lambda/defer.py +0 -0
  14. {async-lambda-unstable-0.4.18 → async-lambda-unstable-0.5.2}/async_lambda/middleware.py +0 -0
  15. {async-lambda-unstable-0.4.18 → async-lambda-unstable-0.5.2}/async_lambda/models/__init__.py +0 -0
  16. {async-lambda-unstable-0.4.18 → async-lambda-unstable-0.5.2}/async_lambda/models/api_response.py +0 -0
  17. {async-lambda-unstable-0.4.18 → async-lambda-unstable-0.5.2}/async_lambda/models/case_insensitive_dict.py +0 -0
  18. {async-lambda-unstable-0.4.18 → async-lambda-unstable-0.5.2}/async_lambda/models/events/__init__.py +0 -0
  19. {async-lambda-unstable-0.4.18 → async-lambda-unstable-0.5.2}/async_lambda/models/events/api_event.py +0 -0
  20. {async-lambda-unstable-0.4.18 → async-lambda-unstable-0.5.2}/async_lambda/models/events/base_event.py +0 -0
  21. {async-lambda-unstable-0.4.18 → async-lambda-unstable-0.5.2}/async_lambda/models/events/dynamodb_event.py +0 -0
  22. {async-lambda-unstable-0.4.18 → async-lambda-unstable-0.5.2}/async_lambda/models/events/managed_sqs_batch_event.py +0 -0
  23. {async-lambda-unstable-0.4.18 → async-lambda-unstable-0.5.2}/async_lambda/models/events/managed_sqs_event.py +0 -0
  24. {async-lambda-unstable-0.4.18 → async-lambda-unstable-0.5.2}/async_lambda/models/events/scheduled_event.py +0 -0
  25. {async-lambda-unstable-0.4.18 → async-lambda-unstable-0.5.2}/async_lambda/models/events/unmanaged_sqs_event.py +0 -0
  26. {async-lambda-unstable-0.4.18 → async-lambda-unstable-0.5.2}/async_lambda/models/mock/mock_context.py +0 -0
  27. {async-lambda-unstable-0.4.18 → async-lambda-unstable-0.5.2}/async_lambda/models/mock/mock_event.py +0 -0
  28. {async-lambda-unstable-0.4.18 → async-lambda-unstable-0.5.2}/async_lambda/payload_encoder.py +0 -0
  29. {async-lambda-unstable-0.4.18 → async-lambda-unstable-0.5.2}/async_lambda/py.typed +0 -0
  30. {async-lambda-unstable-0.4.18 → async-lambda-unstable-0.5.2}/async_lambda/util.py +0 -0
  31. {async-lambda-unstable-0.4.18 → async-lambda-unstable-0.5.2}/async_lambda_unstable.egg-info/SOURCES.txt +0 -0
  32. {async-lambda-unstable-0.4.18 → async-lambda-unstable-0.5.2}/async_lambda_unstable.egg-info/dependency_links.txt +0 -0
  33. {async-lambda-unstable-0.4.18 → async-lambda-unstable-0.5.2}/async_lambda_unstable.egg-info/entry_points.txt +0 -0
  34. {async-lambda-unstable-0.4.18 → async-lambda-unstable-0.5.2}/async_lambda_unstable.egg-info/requires.txt +0 -0
  35. {async-lambda-unstable-0.4.18 → async-lambda-unstable-0.5.2}/async_lambda_unstable.egg-info/top_level.txt +0 -0
  36. {async-lambda-unstable-0.4.18 → async-lambda-unstable-0.5.2}/pyproject.toml +0 -0
  37. {async-lambda-unstable-0.4.18 → async-lambda-unstable-0.5.2}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: async-lambda-unstable
3
- Version: 0.4.18
3
+ Version: 0.5.2
4
4
  Summary: A framework for creating AWS Lambda Async Workflows. - Unstable Branch
5
5
  Author-email: "Nuclei, Inc" <engineering@nuclei.ai>
6
6
  Description-Content-Type: text/markdown
@@ -19,4 +19,4 @@ from .models.events.managed_sqs_event import ManagedSQSEvent as ManagedSQSEvent
19
19
  from .models.events.scheduled_event import ScheduledEvent as ScheduledEvent
20
20
  from .models.events.unmanaged_sqs_event import UnmanagedSQSEvent as UnmanagedSQSEvent
21
21
 
22
- __version__ = "0.4.18"
22
+ __version__ = "0.5.2"
@@ -7,10 +7,12 @@ import boto3
7
7
  class Clients:
8
8
  s3_client: Optional[Any] = None
9
9
  sqs_client: Optional[Any] = None
10
+ sts_client: Optional[Any] = None
10
11
 
11
12
  def reset(self):
12
13
  self.s3_client = None
13
14
  self.sqs_client = None
15
+ self.sts_client = None
14
16
 
15
17
 
16
18
  clients = Clients()
@@ -33,3 +35,9 @@ def get_sqs_client():
33
35
  if clients.sqs_client is None:
34
36
  clients.sqs_client = boto3.client("sqs", **get_client_kwargs())
35
37
  return clients.sqs_client
38
+
39
+
40
+ def get_sts_client():
41
+ if clients.sts_client is None:
42
+ clients.sts_client = boto3.client("sts", **get_client_kwargs())
43
+ return clients.sts_client
@@ -4,7 +4,18 @@ import logging
4
4
  import re
5
5
  import time
6
6
  from datetime import datetime, timezone
7
- from typing import Any, Callable, Dict, List, Optional, Sequence, Type, TypeVar, Union
7
+ from typing import (
8
+ Any,
9
+ Callable,
10
+ Dict,
11
+ List,
12
+ Optional,
13
+ Sequence,
14
+ Set,
15
+ Type,
16
+ TypeVar,
17
+ Union,
18
+ )
8
19
  from uuid import uuid4
9
20
 
10
21
  from . import env
@@ -41,6 +52,7 @@ class AsyncLambdaController:
41
52
  lane_count: Optional[int] = None
42
53
  propagate_lane_assignment: Optional[bool] = None
43
54
  tasks: Dict[str, AsyncLambdaTask]
55
+ external_async_tasks: Set[str]
44
56
  current_task_id: Optional[str] = None
45
57
  current_lane: Optional[int] = None
46
58
  current_invocation_id: Optional[str] = None
@@ -61,6 +73,7 @@ class AsyncLambdaController:
61
73
  controller_name: Optional[str] = None,
62
74
  ):
63
75
  self.tasks = dict()
76
+ self.external_async_tasks = set()
64
77
  self.is_sub = is_sub
65
78
  self.lane_count = lane_count
66
79
  self.propagate_lane_assignment = propagate_lane_assignment
@@ -97,6 +110,16 @@ class AsyncLambdaController:
97
110
  )
98
111
  self.tasks[task.task_id] = task
99
112
 
113
+ def add_external_task(self, external_task_id: str):
114
+ """
115
+ Adds an external task to the controller, which will then be enabled to async_invoke.
116
+
117
+ `external_task_id` is `{config.name}-{task_id}` of the external task (the queue name)
118
+
119
+ Sending payloads via S3 is not currently supported with external tasks.
120
+ """
121
+ self.external_async_tasks.add(external_task_id)
122
+
100
123
  def get_lane_count(self) -> int:
101
124
  if self.lane_count is not None:
102
125
  return self.lane_count
@@ -193,7 +216,11 @@ class AsyncLambdaController:
193
216
  if task.trigger_type == TaskTriggerType.API_EVENT:
194
217
  has_api_tasks = True
195
218
  for logical_id, resource in task.get_sam_template(
196
- module, _task_list, config_dict, stage
219
+ module=module,
220
+ tasks=_task_list,
221
+ external_async_tasks=self.external_async_tasks,
222
+ config_dict=config_dict,
223
+ stage=stage,
197
224
  ).items():
198
225
  template["Resources"][logical_id] = resource
199
226
 
@@ -354,28 +381,44 @@ class AsyncLambdaController:
354
381
  force_sync=force_sync,
355
382
  lane=lane,
356
383
  )
384
+ is_external_task = False
357
385
  if destination_task_id not in self.tasks:
358
- raise Exception(
359
- f"No such task exists with the task_id {destination_task_id}"
360
- )
386
+ if destination_task_id in self.external_async_tasks:
387
+ is_external_task = True
388
+ else:
389
+ raise Exception(
390
+ f"No such task exists with the task_id {destination_task_id}"
391
+ )
392
+ if not is_external_task:
393
+ destination_task = self.tasks[destination_task_id]
394
+ if destination_task.trigger_type not in MANAGED_SQS_TASK_TYPES:
395
+ raise Exception(
396
+ f"Unable to invoke task '{destination_task_id}' because it is a {destination_task.trigger_type} task"
397
+ )
361
398
 
362
- destination_task = self.tasks[destination_task_id]
363
- if destination_task.trigger_type not in MANAGED_SQS_TASK_TYPES:
364
- raise Exception(
365
- f"Unable to invoke task '{destination_task_id}' because it is a {destination_task.trigger_type} task"
366
- )
399
+ if lane is None and destination_task.should_propagate_lane_assignment():
400
+ lane = self.get_current_lane()
401
+ if lane is None:
402
+ lane = 0
367
403
 
368
- if lane is None and destination_task.should_propagate_lane_assignment():
369
- lane = self.get_current_lane()
370
- if lane is None:
404
+ if lane < 0 or lane >= destination_task.get_lane_count():
405
+ raise Exception(
406
+ f"Unable to invoke task {destination_task_id} in lane {lane} because it is not a valid lane for the task."
407
+ )
408
+ else:
409
+ if lane is None:
410
+ lane = self.get_current_lane()
411
+ if lane != 0:
412
+ logger.warning(
413
+ f"Selected lane is {lane}. External tasks only support lane 0."
414
+ )
371
415
  lane = 0
372
416
 
373
- if lane < 0 or lane >= destination_task.get_lane_count():
374
- raise Exception(
375
- f"Unable to invoke task {destination_task_id} in lane {lane} because it is not a valid lane for the task."
376
- )
377
-
378
417
  if force_sync or env.get_force_sync_mode():
418
+ if is_external_task:
419
+ raise NotImplementedError(
420
+ f"Unable to run external task {destination_task_id} locally."
421
+ )
379
422
  if delay:
380
423
  time.sleep(delay)
381
424
  # Sync invocation with mock event/context
@@ -393,8 +436,12 @@ class AsyncLambdaController:
393
436
  self.set_current_lane(current_lane)
394
437
  return result
395
438
  else:
439
+ if is_external_task:
440
+ url = f"https://sqs.{env.get_aws_region()}.amazonaws.com/{env.get_aws_account_id()}/{destination_task_id}"
441
+ else:
442
+ url = destination_task.get_managed_queue_url(lane=lane)
396
443
  get_sqs_client().send_message(
397
- QueueUrl=destination_task.get_managed_queue_url(lane=lane),
444
+ QueueUrl=url,
398
445
  MessageBody=json.dumps(sqs_payload),
399
446
  DelaySeconds=delay,
400
447
  )
@@ -419,29 +466,45 @@ class AsyncLambdaController:
419
466
  force_sync=force_sync,
420
467
  lane=lane,
421
468
  )
469
+
470
+ is_external_task = False
422
471
  if destination_task_id not in self.tasks:
423
- raise Exception(
424
- f"No such task exists with the task_id {destination_task_id}"
425
- )
472
+ if destination_task_id in self.external_async_tasks:
473
+ is_external_task = True
474
+ else:
475
+ raise Exception(
476
+ f"No such task exists with the task_id {destination_task_id}"
477
+ )
478
+ if not is_external_task:
479
+ destination_task = self.tasks[destination_task_id]
480
+ if destination_task.trigger_type not in MANAGED_SQS_TASK_TYPES:
481
+ raise Exception(
482
+ f"Unable to invoke task '{destination_task_id}' because it is a {destination_task.trigger_type} task"
483
+ )
426
484
 
427
- destination_task = self.tasks[destination_task_id]
428
- if destination_task.trigger_type not in MANAGED_SQS_TASK_TYPES:
429
- raise Exception(
430
- f"Unable to invoke task '{destination_task_id}' because it is a {destination_task.trigger_type} task"
431
- )
485
+ if lane is None and destination_task.should_propagate_lane_assignment():
486
+ lane = self.get_current_lane()
487
+ if lane is None:
488
+ lane = 0
432
489
 
433
- if lane is None and destination_task.should_propagate_lane_assignment():
434
- lane = self.get_current_lane()
435
- if lane is None:
490
+ if lane < 0 or lane >= destination_task.get_lane_count():
491
+ raise Exception(
492
+ f"Unable to invoke task {destination_task_id} in lane {lane} because it is not a valid lane for the task."
493
+ )
494
+ else:
495
+ if lane is None:
496
+ lane = self.get_current_lane()
497
+ if lane != 0:
498
+ logger.warning(
499
+ f"Selected lane is {lane}. External tasks only support lane 0."
500
+ )
436
501
  lane = 0
437
502
 
438
- if lane < 0 or lane >= destination_task.get_lane_count():
439
- raise Exception(
440
- f"Unable to invoke task {destination_task_id} in lane {lane} because it is not a valid lane for the task."
441
- )
442
-
443
503
  if force_sync or env.get_force_sync_mode():
444
-
504
+ if is_external_task:
505
+ raise NotImplementedError(
506
+ f"Unable to run external task {destination_task_id} locally."
507
+ )
445
508
  # Sync invocation with mock event/context
446
509
  current_task_id = self.current_task_id
447
510
  current_lane = self.get_current_lane()
@@ -462,7 +525,7 @@ class AsyncLambdaController:
462
525
  self.set_current_lane(current_lane)
463
526
  self.set_current_task_id(current_task_id)
464
527
  else:
465
- entries = []
528
+ entries: List[dict] = []
466
529
  for i, sqs_payload in enumerate(sqs_payloads):
467
530
  if isinstance(delay, Sequence):
468
531
  _delay = delay[i]
@@ -475,13 +538,27 @@ class AsyncLambdaController:
475
538
  "Id": f"index_{index + i}",
476
539
  }
477
540
  )
478
- response = get_sqs_client().send_message_batch(
479
- QueueUrl=destination_task.get_managed_queue_url(lane=lane),
480
- Entries=entries,
481
- )
482
- if len(response.get("Failed", [])) > 0:
483
- logger.error(response["Failed"])
484
- raise Exception(f"Failed to send {len(response['Failed'])} messages.")
541
+ if is_external_task:
542
+ url = f"https://sqs.{env.get_aws_region()}.amazonaws.com/{env.get_aws_account_id()}/{destination_task_id}"
543
+ else:
544
+ url = destination_task.get_managed_queue_url(lane=lane)
545
+ failed_messages = []
546
+ for _ in range(5):
547
+ response = get_sqs_client().send_message_batch(
548
+ QueueUrl=url,
549
+ Entries=entries,
550
+ )
551
+ failed_messages: List[dict] = response.get("Failed", [])
552
+ if len(failed_messages) == 0:
553
+ return
554
+ logger.warning(failed_messages)
555
+ logger.warning(f"{len(failed_messages)} messages failed to send.")
556
+ failed_message_ids = {message["Id"] for message in failed_messages}
557
+ entries = [
558
+ entry for entry in entries if entry["Id"] in failed_message_ids
559
+ ]
560
+ logger.error(failed_messages)
561
+ raise Exception(f"Failed to send {len(failed_messages)} messages.")
485
562
 
486
563
  def new_payload(
487
564
  self,
@@ -504,6 +581,14 @@ class AsyncLambdaController:
504
581
  "destination_task_id": destination_task_id,
505
582
  "invocation_id": invocation_id,
506
583
  }
584
+ is_external_task = False
585
+ if (
586
+ self.get_task(destination_task_id) is None
587
+ and destination_task_id in self.external_async_tasks
588
+ ):
589
+ is_external_task = True
590
+ raw_sqs_body["source_app"] = config.name
591
+
507
592
  serialized_payload = json.dumps(payload, cls=PayloadEncoder)
508
593
  payload_size = len(serialized_payload.encode())
509
594
  if payload_size < 250_000: # we need to double encode to be sure
@@ -512,6 +597,10 @@ class AsyncLambdaController:
512
597
  if force_sync or env.get_force_sync_mode():
513
598
  raw_sqs_body["payload"] = serialized_payload
514
599
  elif payload_size >= 250_000: # payload is bigger than max SQS size
600
+ if is_external_task:
601
+ raise NotImplementedError(
602
+ "Payload is too large for SQS and S3 payloads are not supported with external invocations"
603
+ )
515
604
  date_part = datetime.now(tz=timezone.utc).strftime("%Y/%m/%d")
516
605
  key = f"{date_part}/{uuid4().hex}.json"
517
606
  logger.info(f"Utilizing S3 Payload because of payload size. Key: {key}")
@@ -529,6 +618,9 @@ class AsyncLambdaController:
529
618
  for task in controller.tasks.values():
530
619
  self.add_task(task)
531
620
 
621
+ for task_id in controller.external_async_tasks:
622
+ self.external_async_tasks.add(task_id)
623
+
532
624
  def async_invoke(
533
625
  self,
534
626
  task_id: str,
@@ -0,0 +1,81 @@
1
+ import logging
2
+ import os
3
+ from typing import Optional
4
+
5
+ from .client import get_sts_client
6
+
7
+
8
+ class AWSConfig:
9
+ _aws_region: Optional[str] = None
10
+ _account_id: Optional[str] = None
11
+
12
+ @property
13
+ def aws_region(self):
14
+ if self._aws_region:
15
+ return self._aws_region
16
+ self._aws_region = os.environ.get(
17
+ "AWS_REGION", os.environ.get("AWS_DEFAULT_REGION")
18
+ )
19
+ if self._aws_region is None:
20
+ raise ValueError("Unable to find AWS_REGION for constructing ARN or URL")
21
+ return self._aws_region
22
+
23
+ @property
24
+ def account_id(self):
25
+ if self._account_id:
26
+ return self._account_id
27
+ self._account_id = os.environ.get("ASYNC_LAMBDA_ACCOUNT_ID")
28
+ if self._account_id is not None:
29
+ return self._account_id
30
+ self._account_id = get_sts_client().get_caller_identity().get("Account")
31
+ logging.info(f"Fetched account_id from sts: {self._account_id}")
32
+ if self._account_id is None:
33
+ raise ValueError("Unable to get ACCOUNT_ID from env or STS.")
34
+ return self._account_id
35
+
36
+ def reset(self):
37
+ self._aws_region = None
38
+ self._account_id = None
39
+
40
+
41
+ aws_config = AWSConfig()
42
+
43
+
44
+ def reset():
45
+ aws_config.reset()
46
+
47
+
48
+ def is_build_mode() -> bool:
49
+ return bool(os.environ.get("ASYNC_LAMBDA_BUILD_MODE", False))
50
+
51
+
52
+ def get_aws_region() -> str:
53
+ return aws_config.aws_region
54
+
55
+
56
+ def get_aws_account_id() -> str:
57
+ return aws_config.account_id
58
+
59
+
60
+ def get_payload_bucket() -> str:
61
+ return os.environ["ASYNC_LAMBDA_PAYLOAD_S3_BUCKET"]
62
+
63
+
64
+ def get_current_task_id() -> str:
65
+ return os.environ["ASYNC_LAMBDA_TASK_ID"]
66
+
67
+
68
+ def is_cloud() -> bool:
69
+ return bool(os.environ.get("AWS_LAMBDA_FUNCTION_NAME"))
70
+
71
+
72
+ def enable_force_sync_mode():
73
+ os.environ["ASYNC_LAMBDA_FORCE_SYNC"] = "1"
74
+
75
+
76
+ def disable_force_sync_mode():
77
+ del os.environ["ASYNC_LAMBDA_FORCE_SYNC"]
78
+
79
+
80
+ def get_force_sync_mode() -> bool:
81
+ return bool(os.environ.get("ASYNC_LAMBDA_FORCE_SYNC", ""))
@@ -2,7 +2,17 @@ import inspect
2
2
  import json
3
3
  import re
4
4
  from enum import Enum
5
- from typing import TYPE_CHECKING, Any, Callable, Generic, List, Optional, TypeVar, Union
5
+ from typing import (
6
+ TYPE_CHECKING,
7
+ Any,
8
+ Callable,
9
+ Generic,
10
+ List,
11
+ Optional,
12
+ Set,
13
+ TypeVar,
14
+ Union,
15
+ )
6
16
 
7
17
  from async_lambda.util import make_cf_tags
8
18
 
@@ -322,10 +332,21 @@ class AsyncLambdaTask(Generic[EventType, RT]):
322
332
  return [self.trigger_config["queue_arn"]]
323
333
  return []
324
334
 
335
+ @classmethod
336
+ def get_policy_external_task_resources(cls, external_task_id: str) -> list:
337
+ return [
338
+ {
339
+ "Fn::Sub": "arn:aws:sqs:${AWS::Region}:${AWS::AccountId}:external_task_id".replace(
340
+ "external_task_id", external_task_id
341
+ )
342
+ }
343
+ ]
344
+
325
345
  def get_sam_template(
326
346
  self,
327
347
  module: str,
328
348
  tasks: List["AsyncLambdaTask"],
349
+ external_async_tasks: Set[str],
329
350
  config_dict: dict,
330
351
  stage: Optional[str] = None,
331
352
  ) -> dict:
@@ -358,6 +379,12 @@ class AsyncLambdaTask(Generic[EventType, RT]):
358
379
  for task in tasks
359
380
  if task.trigger_type in MANAGED_SQS_TASK_TYPES
360
381
  for resource in task.get_policy_sqs_resources()
382
+ ] + [
383
+ resource
384
+ for external_async_task_id in external_async_tasks
385
+ for resource in self.get_policy_external_task_resources(
386
+ external_async_task_id
387
+ )
361
388
  ]
362
389
  if len(managed_tasks_resources) > 0:
363
390
  policy_statements.append(
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: async-lambda-unstable
3
- Version: 0.4.18
3
+ Version: 0.5.2
4
4
  Summary: A framework for creating AWS Lambda Async Workflows. - Unstable Branch
5
5
  Author-email: "Nuclei, Inc" <engineering@nuclei.ai>
6
6
  Description-Content-Type: text/markdown
@@ -1,37 +0,0 @@
1
- import os
2
-
3
-
4
- def is_build_mode() -> bool:
5
- return bool(os.environ.get("ASYNC_LAMBDA_BUILD_MODE", False))
6
-
7
-
8
- def get_aws_region() -> str:
9
- return os.environ.get("AWS_REGION", "local")
10
-
11
-
12
- def get_aws_account_id() -> str:
13
- return os.environ.get("ASYNC_LAMBDA_ACCOUNT_ID", "localaccount")
14
-
15
-
16
- def get_payload_bucket() -> str:
17
- return os.environ["ASYNC_LAMBDA_PAYLOAD_S3_BUCKET"]
18
-
19
-
20
- def get_current_task_id() -> str:
21
- return os.environ["ASYNC_LAMBDA_TASK_ID"]
22
-
23
-
24
- def is_cloud() -> bool:
25
- return bool(os.environ.get("AWS_LAMBDA_FUNCTION_NAME"))
26
-
27
-
28
- def enable_force_sync_mode():
29
- os.environ["ASYNC_LAMBDA_FORCE_SYNC"] = "1"
30
-
31
-
32
- def disable_force_sync_mode():
33
- del os.environ["ASYNC_LAMBDA_FORCE_SYNC"]
34
-
35
-
36
- def get_force_sync_mode() -> bool:
37
- return bool(os.environ.get("ASYNC_LAMBDA_FORCE_SYNC", ""))