• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

localstack / localstack / 20565403496

29 Dec 2025 05:11AM UTC coverage: 84.103% (-2.8%) from 86.921%
20565403496

Pull #13567

github

web-flow
Merge 4816837a5 into 2417384aa
Pull Request #13567: Update ASF APIs

67166 of 79862 relevant lines covered (84.1%)

0.84 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

93.33
/localstack-core/localstack/aws/handlers/service_plugin.py
1
"""Handlers extending the base logic of service handlers with lazy-loading and plugin mechanisms."""
2

3
import logging
1✔
4
import threading
1✔
5

6
from localstack.http import Response
1✔
7
from localstack.services.plugins import Service, ServiceManager
1✔
8
from localstack.utils.sync import SynchronizedDefaultDict
1✔
9

10
from ...utils.bootstrap import is_api_enabled
1✔
11
from ..api import RequestContext
1✔
12
from ..chain import Handler, HandlerChain
1✔
13
from ..protocol.service_router import determine_aws_service_model_for_data_plane
1✔
14
from .service import ServiceRequestRouter
1✔
15

16
LOG = logging.getLogger(__name__)
1✔
17

18

19
class ServiceLoader(Handler):
1✔
20
    def __init__(
1✔
21
        self, service_manager: ServiceManager, service_request_router: ServiceRequestRouter
22
    ):
23
        """
24
        This handler encapsulates service lazy-loading. It loads services from the given ServiceManager and uses them
25
        to populate the given ServiceRequestRouter.
26

27
        :param service_manager: the service manager used to load services
28
        :param service_request_router: the service request router to populate
29
        """
30
        self.service_manager = service_manager
1✔
31
        self.service_request_router = service_request_router
1✔
32
        self.service_locks = SynchronizedDefaultDict(threading.RLock)
1✔
33
        self.loaded_services = set()
1✔
34

35
    def __call__(self, chain: HandlerChain, context: RequestContext, response: Response):
1✔
36
        return self.require_service(chain, context, response)
1✔
37

38
    def require_service(self, _: HandlerChain, context: RequestContext, response: Response):
1✔
39
        if not context.service:
1✔
40
            return
×
41

42
        service_name: str = context.service.service_name
1✔
43
        if service_name in self.loaded_services:
1✔
44
            return
1✔
45

46
        if not self.service_manager.exists(service_name):
1✔
47
            raise NotImplementedError
48
        elif not is_api_enabled(service_name):
1✔
49
            raise NotImplementedError(
50
                f"Service '{service_name}' is not enabled. Please check your 'SERVICES' configuration variable."
51
            )
52

53
        request_router = self.service_request_router
1✔
54

55
        # Ensure the Service is loaded and set to ServiceState.RUNNING if not in an erroneous state.
56
        service_plugin: Service = self.service_manager.require(service_name)
1✔
57

58
        with self.service_locks[context.service.service_name]:
1✔
59
            # try again to avoid race conditions
60
            if service_name in self.loaded_services:
1✔
61
                return
1✔
62
            self.loaded_services.add(service_name)
1✔
63
            if isinstance(service_plugin, Service):
1✔
64
                request_router.add_skeleton(service_plugin.skeleton)
1✔
65
            else:
66
                LOG.warning(
×
67
                    "found plugin for '%s', but cannot attach service plugin of type '%s'",
68
                    service_name,
69
                    type(service_plugin),
70
                )
71

72

73
class ServiceLoaderForDataPlane(Handler):
1✔
74
    """
75
    Specific lightweight service loader that loads services based only on hostname indicators. This allows
76
    us to correctly load services when things like lambda function URLs or APIGW REST APIs are called
77
    before the services were actually loaded.
78
    """
79

80
    def __init__(self, service_loader: ServiceLoader):
1✔
81
        self.service_loader = service_loader
1✔
82

83
    def __call__(self, chain: HandlerChain, context: RequestContext, response: Response):
1✔
84
        if context.service:
1✔
85
            return
×
86

87
        if service := determine_aws_service_model_for_data_plane(context.request):
1✔
88
            context.service = service
1✔
89
            self.service_loader.require_service(chain, context, response)
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc