ominfra 0.0.0.dev124__py3-none-any.whl → 0.0.0.dev125__py3-none-any.whl
Sign up to get free protection for your applications and to get access to all the features.
- ominfra/deploy/poly/_main.py +2 -6
- ominfra/deploy/poly/base.py +7 -8
- ominfra/scripts/supervisor.py +265 -148
- ominfra/supervisor/LICENSE.txt +19 -19
- ominfra/supervisor/context.py +5 -5
- ominfra/supervisor/dispatchers.py +5 -5
- ominfra/supervisor/events.py +3 -3
- ominfra/supervisor/groups.py +12 -18
- ominfra/supervisor/inject.py +10 -27
- ominfra/supervisor/main.py +30 -2
- ominfra/supervisor/process.py +8 -8
- ominfra/supervisor/supervisor.py +11 -16
- ominfra/supervisor/types.py +51 -6
- {ominfra-0.0.0.dev124.dist-info → ominfra-0.0.0.dev125.dist-info}/METADATA +3 -3
- {ominfra-0.0.0.dev124.dist-info → ominfra-0.0.0.dev125.dist-info}/RECORD +19 -19
- {ominfra-0.0.0.dev124.dist-info → ominfra-0.0.0.dev125.dist-info}/LICENSE +0 -0
- {ominfra-0.0.0.dev124.dist-info → ominfra-0.0.0.dev125.dist-info}/WHEEL +0 -0
- {ominfra-0.0.0.dev124.dist-info → ominfra-0.0.0.dev125.dist-info}/entry_points.txt +0 -0
- {ominfra-0.0.0.dev124.dist-info → ominfra-0.0.0.dev125.dist-info}/top_level.txt +0 -0
ominfra/scripts/supervisor.py
CHANGED
@@ -4,6 +4,34 @@
|
|
4
4
|
# @omlish-script
|
5
5
|
# @omlish-amalg-output ../supervisor/main.py
|
6
6
|
# ruff: noqa: N802 UP006 UP007 UP012 UP036
|
7
|
+
# Supervisor is licensed under the following license:
|
8
|
+
#
|
9
|
+
# A copyright notice accompanies this license document that identifies the copyright holders.
|
10
|
+
#
|
11
|
+
# Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
|
12
|
+
# following conditions are met:
|
13
|
+
#
|
14
|
+
# 1. Redistributions in source code must retain the accompanying copyright notice, this list of conditions, and the
|
15
|
+
# following disclaimer.
|
16
|
+
#
|
17
|
+
# 2. Redistributions in binary form must reproduce the accompanying copyright notice, this list of conditions, and the
|
18
|
+
# following disclaimer in the documentation and/or other materials provided with the distribution.
|
19
|
+
#
|
20
|
+
# 3. Names of the copyright holders must not be used to endorse or promote products derived from this software without
|
21
|
+
# prior written permission from the copyright holders.
|
22
|
+
#
|
23
|
+
# 4. If any files are modified, you must cause the modified files to carry prominent notices stating that you changed
|
24
|
+
# the files and the date of any change.
|
25
|
+
#
|
26
|
+
# Disclaimer
|
27
|
+
#
|
28
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
|
29
|
+
# NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
30
|
+
# EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
31
|
+
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
32
|
+
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
33
|
+
# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
34
|
+
# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
7
35
|
import abc
|
8
36
|
import base64
|
9
37
|
import collections.abc
|
@@ -74,6 +102,9 @@ T = ta.TypeVar('T')
|
|
74
102
|
SocketAddress = ta.Any
|
75
103
|
SocketHandlerFactory = ta.Callable[[SocketAddress, ta.BinaryIO, ta.BinaryIO], 'SocketHandler']
|
76
104
|
|
105
|
+
# ../events.py
|
106
|
+
EventCallback = ta.Callable[['Event'], None]
|
107
|
+
|
77
108
|
# ../../../omlish/lite/http/parsing.py
|
78
109
|
HttpHeaders = http.client.HTTPMessage # ta.TypeAlias
|
79
110
|
|
@@ -92,12 +123,6 @@ HttpHandler = ta.Callable[['HttpHandlerRequest'], 'HttpHandlerResponse']
|
|
92
123
|
# ../../../omlish/lite/http/coroserver.py
|
93
124
|
CoroHttpServerFactory = ta.Callable[[SocketAddress], 'CoroHttpServer']
|
94
125
|
|
95
|
-
# ../context.py
|
96
|
-
ServerEpoch = ta.NewType('ServerEpoch', int)
|
97
|
-
|
98
|
-
# ../process.py
|
99
|
-
InheritedFds = ta.NewType('InheritedFds', ta.FrozenSet[int])
|
100
|
-
|
101
126
|
|
102
127
|
########################################
|
103
128
|
# ../../../omdev/toml/parser.py
|
@@ -1537,6 +1562,18 @@ class SocketHandler(abc.ABC):
|
|
1537
1562
|
raise NotImplementedError
|
1538
1563
|
|
1539
1564
|
|
1565
|
+
########################################
|
1566
|
+
# ../../../omlish/lite/typing.py
|
1567
|
+
|
1568
|
+
|
1569
|
+
@dc.dataclass(frozen=True)
|
1570
|
+
class Func(ta.Generic[T]):
|
1571
|
+
fn: ta.Callable[..., T]
|
1572
|
+
|
1573
|
+
def __call__(self, *args: ta.Any, **kwargs: ta.Any) -> T:
|
1574
|
+
return self.fn(*args, **kwargs)
|
1575
|
+
|
1576
|
+
|
1540
1577
|
########################################
|
1541
1578
|
# ../events.py
|
1542
1579
|
|
@@ -1551,9 +1588,6 @@ class Event(abc.ABC): # noqa
|
|
1551
1588
|
##
|
1552
1589
|
|
1553
1590
|
|
1554
|
-
EventCallback = ta.Callable[['Event'], None]
|
1555
|
-
|
1556
|
-
|
1557
1591
|
class EventCallbacks:
|
1558
1592
|
def __init__(self) -> None:
|
1559
1593
|
super().__init__()
|
@@ -2398,7 +2432,13 @@ class HttpRequestParser:
|
|
2398
2432
|
|
2399
2433
|
@dc.dataclass(frozen=True)
|
2400
2434
|
class InjectorKey(ta.Generic[T]):
|
2401
|
-
cls
|
2435
|
+
# Before PEP-560 typing.Generic was a metaclass with a __new__ that takes a 'cls' arg, so instantiating a dataclass
|
2436
|
+
# with kwargs (such as through dc.replace) causes `TypeError: __new__() got multiple values for argument 'cls'`.
|
2437
|
+
# See:
|
2438
|
+
# - https://github.com/python/cpython/commit/d911e40e788fb679723d78b6ea11cabf46caed5a
|
2439
|
+
# - https://gist.github.com/wrmsr/4468b86efe9f373b6b114bfe85b98fd3
|
2440
|
+
cls_: InjectorKeyCls
|
2441
|
+
|
2402
2442
|
tag: ta.Any = None
|
2403
2443
|
array: bool = False
|
2404
2444
|
|
@@ -2519,14 +2559,14 @@ class FnInjectorProvider(InjectorProvider):
|
|
2519
2559
|
|
2520
2560
|
@dc.dataclass(frozen=True)
|
2521
2561
|
class CtorInjectorProvider(InjectorProvider):
|
2522
|
-
|
2562
|
+
cls_: type
|
2523
2563
|
|
2524
2564
|
def __post_init__(self) -> None:
|
2525
|
-
check_isinstance(self.
|
2565
|
+
check_isinstance(self.cls_, type)
|
2526
2566
|
|
2527
2567
|
def provider_fn(self) -> InjectorProviderFn:
|
2528
2568
|
def pfn(i: Injector) -> ta.Any:
|
2529
|
-
return i.inject(self.
|
2569
|
+
return i.inject(self.cls_)
|
2530
2570
|
|
2531
2571
|
return pfn
|
2532
2572
|
|
@@ -2675,19 +2715,42 @@ def build_injector_provider_map(bs: InjectorBindings) -> ta.Mapping[InjectorKey,
|
|
2675
2715
|
# inspection
|
2676
2716
|
|
2677
2717
|
|
2678
|
-
|
2718
|
+
# inspect.signature(eval_str=True) was added in 3.10 and we have to support 3.8, so we have to get_type_hints to eval
|
2719
|
+
# str annotations *in addition to* getting the signature for parameter information.
|
2720
|
+
class _InjectionInspection(ta.NamedTuple):
|
2721
|
+
signature: inspect.Signature
|
2722
|
+
type_hints: ta.Mapping[str, ta.Any]
|
2723
|
+
|
2679
2724
|
|
2725
|
+
_INJECTION_INSPECTION_CACHE: ta.MutableMapping[ta.Any, _InjectionInspection] = weakref.WeakKeyDictionary()
|
2680
2726
|
|
2681
|
-
|
2727
|
+
|
2728
|
+
def _do_injection_inspect(obj: ta.Any) -> _InjectionInspection:
|
2729
|
+
uw = obj
|
2730
|
+
while True:
|
2731
|
+
if isinstance(uw, functools.partial):
|
2732
|
+
uw = uw.func
|
2733
|
+
else:
|
2734
|
+
if (uw2 := inspect.unwrap(uw)) is uw:
|
2735
|
+
break
|
2736
|
+
uw = uw2
|
2737
|
+
|
2738
|
+
return _InjectionInspection(
|
2739
|
+
inspect.signature(obj),
|
2740
|
+
ta.get_type_hints(uw),
|
2741
|
+
)
|
2742
|
+
|
2743
|
+
|
2744
|
+
def _injection_inspect(obj: ta.Any) -> _InjectionInspection:
|
2682
2745
|
try:
|
2683
|
-
return
|
2746
|
+
return _INJECTION_INSPECTION_CACHE[obj]
|
2684
2747
|
except TypeError:
|
2685
|
-
return
|
2748
|
+
return _do_injection_inspect(obj)
|
2686
2749
|
except KeyError:
|
2687
2750
|
pass
|
2688
|
-
|
2689
|
-
|
2690
|
-
return
|
2751
|
+
insp = _do_injection_inspect(obj)
|
2752
|
+
_INJECTION_INSPECTION_CACHE[obj] = insp
|
2753
|
+
return insp
|
2691
2754
|
|
2692
2755
|
|
2693
2756
|
class InjectionKwarg(ta.NamedTuple):
|
@@ -2708,20 +2771,20 @@ def build_injection_kwargs_target(
|
|
2708
2771
|
skip_kwargs: ta.Optional[ta.Iterable[ta.Any]] = None,
|
2709
2772
|
raw_optional: bool = False,
|
2710
2773
|
) -> InjectionKwargsTarget:
|
2711
|
-
|
2774
|
+
insp = _injection_inspect(obj)
|
2712
2775
|
|
2713
2776
|
seen: ta.Set[InjectorKey] = set(map(as_injector_key, skip_kwargs)) if skip_kwargs is not None else set()
|
2714
2777
|
kws: ta.List[InjectionKwarg] = []
|
2715
|
-
for p in list(
|
2778
|
+
for p in list(insp.signature.parameters.values())[skip_args:]:
|
2716
2779
|
if p.annotation is inspect.Signature.empty:
|
2717
2780
|
if p.default is not inspect.Parameter.empty:
|
2718
2781
|
raise KeyError(f'{obj}, {p.name}')
|
2719
2782
|
continue
|
2720
2783
|
|
2721
2784
|
if p.kind not in (inspect.Parameter.POSITIONAL_OR_KEYWORD, inspect.Parameter.KEYWORD_ONLY):
|
2722
|
-
raise TypeError(
|
2785
|
+
raise TypeError(insp)
|
2723
2786
|
|
2724
|
-
ann = p.annotation
|
2787
|
+
ann = insp.type_hints.get(p.name, p.annotation)
|
2725
2788
|
if (
|
2726
2789
|
not raw_optional and
|
2727
2790
|
is_optional_alias(ann)
|
@@ -2746,6 +2809,66 @@ def build_injection_kwargs_target(
|
|
2746
2809
|
)
|
2747
2810
|
|
2748
2811
|
|
2812
|
+
###
|
2813
|
+
# injector
|
2814
|
+
|
2815
|
+
|
2816
|
+
_INJECTOR_INJECTOR_KEY: InjectorKey[Injector] = InjectorKey(Injector)
|
2817
|
+
|
2818
|
+
|
2819
|
+
class _Injector(Injector):
|
2820
|
+
def __init__(self, bs: InjectorBindings, p: ta.Optional[Injector] = None) -> None:
|
2821
|
+
super().__init__()
|
2822
|
+
|
2823
|
+
self._bs = check_isinstance(bs, InjectorBindings)
|
2824
|
+
self._p: ta.Optional[Injector] = check_isinstance(p, (Injector, type(None)))
|
2825
|
+
|
2826
|
+
self._pfm = {k: v.provider_fn() for k, v in build_injector_provider_map(bs).items()}
|
2827
|
+
|
2828
|
+
if _INJECTOR_INJECTOR_KEY in self._pfm:
|
2829
|
+
raise DuplicateInjectorKeyError(_INJECTOR_INJECTOR_KEY)
|
2830
|
+
|
2831
|
+
def try_provide(self, key: ta.Any) -> Maybe[ta.Any]:
|
2832
|
+
key = as_injector_key(key)
|
2833
|
+
|
2834
|
+
if key == _INJECTOR_INJECTOR_KEY:
|
2835
|
+
return Maybe.just(self)
|
2836
|
+
|
2837
|
+
fn = self._pfm.get(key)
|
2838
|
+
if fn is not None:
|
2839
|
+
return Maybe.just(fn(self))
|
2840
|
+
|
2841
|
+
if self._p is not None:
|
2842
|
+
pv = self._p.try_provide(key)
|
2843
|
+
if pv is not None:
|
2844
|
+
return Maybe.empty()
|
2845
|
+
|
2846
|
+
return Maybe.empty()
|
2847
|
+
|
2848
|
+
def provide(self, key: ta.Any) -> ta.Any:
|
2849
|
+
v = self.try_provide(key)
|
2850
|
+
if v.present:
|
2851
|
+
return v.must()
|
2852
|
+
raise UnboundInjectorKeyError(key)
|
2853
|
+
|
2854
|
+
def provide_kwargs(self, obj: ta.Any) -> ta.Mapping[str, ta.Any]:
|
2855
|
+
kt = build_injection_kwargs_target(obj)
|
2856
|
+
ret: ta.Dict[str, ta.Any] = {}
|
2857
|
+
for kw in kt.kwargs:
|
2858
|
+
if kw.has_default:
|
2859
|
+
if not (mv := self.try_provide(kw.key)).present:
|
2860
|
+
continue
|
2861
|
+
v = mv.must()
|
2862
|
+
else:
|
2863
|
+
v = self.provide(kw.key)
|
2864
|
+
ret[kw.name] = v
|
2865
|
+
return ret
|
2866
|
+
|
2867
|
+
def inject(self, obj: ta.Any) -> ta.Any:
|
2868
|
+
kws = self.provide_kwargs(obj)
|
2869
|
+
return obj(**kws)
|
2870
|
+
|
2871
|
+
|
2749
2872
|
###
|
2750
2873
|
# binder
|
2751
2874
|
|
@@ -2795,7 +2918,7 @@ class InjectorBinder:
|
|
2795
2918
|
to_key: ta.Any = None,
|
2796
2919
|
|
2797
2920
|
singleton: bool = False,
|
2798
|
-
) ->
|
2921
|
+
) -> InjectorBindingOrBindings:
|
2799
2922
|
if obj is None or obj is inspect.Parameter.empty:
|
2800
2923
|
raise TypeError(obj)
|
2801
2924
|
if isinstance(obj, cls._BANNED_BIND_TYPES):
|
@@ -2825,8 +2948,8 @@ class InjectorBinder:
|
|
2825
2948
|
elif cls._is_fn(obj) and not has_to:
|
2826
2949
|
to_fn = obj
|
2827
2950
|
if key is None:
|
2828
|
-
|
2829
|
-
key_cls = check_valid_injector_key_cls(
|
2951
|
+
insp = _injection_inspect(obj)
|
2952
|
+
key_cls: ta.Any = check_valid_injector_key_cls(check_not_none(insp.type_hints.get('return')))
|
2830
2953
|
key = InjectorKey(key_cls)
|
2831
2954
|
else:
|
2832
2955
|
if to_const is not None:
|
@@ -2878,67 +3001,21 @@ class InjectorBinder:
|
|
2878
3001
|
|
2879
3002
|
|
2880
3003
|
###
|
2881
|
-
#
|
2882
|
-
|
2883
|
-
|
2884
|
-
_INJECTOR_INJECTOR_KEY: InjectorKey[Injector] = InjectorKey(Injector)
|
2885
|
-
|
2886
|
-
|
2887
|
-
class _Injector(Injector):
|
2888
|
-
def __init__(self, bs: InjectorBindings, p: ta.Optional[Injector] = None) -> None:
|
2889
|
-
super().__init__()
|
2890
|
-
|
2891
|
-
self._bs = check_isinstance(bs, InjectorBindings)
|
2892
|
-
self._p: ta.Optional[Injector] = check_isinstance(p, (Injector, type(None)))
|
2893
|
-
|
2894
|
-
self._pfm = {k: v.provider_fn() for k, v in build_injector_provider_map(bs).items()}
|
2895
|
-
|
2896
|
-
if _INJECTOR_INJECTOR_KEY in self._pfm:
|
2897
|
-
raise DuplicateInjectorKeyError(_INJECTOR_INJECTOR_KEY)
|
2898
|
-
|
2899
|
-
def try_provide(self, key: ta.Any) -> Maybe[ta.Any]:
|
2900
|
-
key = as_injector_key(key)
|
2901
|
-
|
2902
|
-
if key == _INJECTOR_INJECTOR_KEY:
|
2903
|
-
return Maybe.just(self)
|
2904
|
-
|
2905
|
-
fn = self._pfm.get(key)
|
2906
|
-
if fn is not None:
|
2907
|
-
return Maybe.just(fn(self))
|
2908
|
-
|
2909
|
-
if self._p is not None:
|
2910
|
-
pv = self._p.try_provide(key)
|
2911
|
-
if pv is not None:
|
2912
|
-
return Maybe.empty()
|
2913
|
-
|
2914
|
-
return Maybe.empty()
|
2915
|
-
|
2916
|
-
def provide(self, key: ta.Any) -> ta.Any:
|
2917
|
-
v = self.try_provide(key)
|
2918
|
-
if v.present:
|
2919
|
-
return v.must()
|
2920
|
-
raise UnboundInjectorKeyError(key)
|
3004
|
+
# injection helpers
|
2921
3005
|
|
2922
|
-
def provide_kwargs(self, obj: ta.Any) -> ta.Mapping[str, ta.Any]:
|
2923
|
-
kt = build_injection_kwargs_target(obj)
|
2924
|
-
ret: ta.Dict[str, ta.Any] = {}
|
2925
|
-
for kw in kt.kwargs:
|
2926
|
-
if kw.has_default:
|
2927
|
-
if not (mv := self.try_provide(kw.key)).present:
|
2928
|
-
continue
|
2929
|
-
v = mv.must()
|
2930
|
-
else:
|
2931
|
-
v = self.provide(kw.key)
|
2932
|
-
ret[kw.name] = v
|
2933
|
-
return ret
|
2934
3006
|
|
2935
|
-
|
2936
|
-
|
2937
|
-
|
3007
|
+
def make_injector_factory(
|
3008
|
+
factory_cls: ta.Any,
|
3009
|
+
factory_fn: ta.Callable[..., T],
|
3010
|
+
) -> ta.Callable[..., Func[T]]:
|
3011
|
+
def outer(injector: Injector) -> factory_cls:
|
3012
|
+
def inner(*args, **kwargs):
|
3013
|
+
return injector.inject(functools.partial(factory_fn, *args, **kwargs))
|
3014
|
+
return Func(inner)
|
3015
|
+
return outer
|
2938
3016
|
|
2939
3017
|
|
2940
|
-
|
2941
|
-
# injection helpers
|
3018
|
+
##
|
2942
3019
|
|
2943
3020
|
|
2944
3021
|
class Injection:
|
@@ -2969,6 +3046,12 @@ class Injection:
|
|
2969
3046
|
def override(cls, p: InjectorBindings, *args: InjectorBindingOrBindings) -> InjectorBindings:
|
2970
3047
|
return injector_override(p, *args)
|
2971
3048
|
|
3049
|
+
# injector
|
3050
|
+
|
3051
|
+
@classmethod
|
3052
|
+
def create_injector(cls, *args: InjectorBindingOrBindings, p: ta.Optional[Injector] = None) -> Injector:
|
3053
|
+
return _Injector(as_injector_bindings(*args), p)
|
3054
|
+
|
2972
3055
|
# binder
|
2973
3056
|
|
2974
3057
|
@classmethod
|
@@ -2986,7 +3069,7 @@ class Injection:
|
|
2986
3069
|
to_key: ta.Any = None,
|
2987
3070
|
|
2988
3071
|
singleton: bool = False,
|
2989
|
-
) ->
|
3072
|
+
) -> InjectorBindingOrBindings:
|
2990
3073
|
return InjectorBinder.bind(
|
2991
3074
|
obj,
|
2992
3075
|
|
@@ -3002,11 +3085,15 @@ class Injection:
|
|
3002
3085
|
singleton=singleton,
|
3003
3086
|
)
|
3004
3087
|
|
3005
|
-
#
|
3088
|
+
# helpers
|
3006
3089
|
|
3007
3090
|
@classmethod
|
3008
|
-
def
|
3009
|
-
|
3091
|
+
def bind_factory(
|
3092
|
+
cls,
|
3093
|
+
factory_cls: ta.Any,
|
3094
|
+
factory_fn: ta.Callable[..., T],
|
3095
|
+
) -> InjectorBindingOrBindings:
|
3096
|
+
return cls.bind(make_injector_factory(factory_cls, factory_fn))
|
3010
3097
|
|
3011
3098
|
|
3012
3099
|
inj = Injection
|
@@ -4790,7 +4877,7 @@ class CoroHttpServerSocketHandler(SocketHandler):
|
|
4790
4877
|
# ../types.py
|
4791
4878
|
|
4792
4879
|
|
4793
|
-
class
|
4880
|
+
class ServerContext(abc.ABC):
|
4794
4881
|
@property
|
4795
4882
|
@abc.abstractmethod
|
4796
4883
|
def config(self) -> ServerConfig:
|
@@ -4807,12 +4894,24 @@ class AbstractServerContext(abc.ABC):
|
|
4807
4894
|
|
4808
4895
|
@property
|
4809
4896
|
@abc.abstractmethod
|
4810
|
-
def pid_history(self) -> ta.Dict[int, '
|
4897
|
+
def pid_history(self) -> ta.Dict[int, 'Process']:
|
4811
4898
|
raise NotImplementedError
|
4812
4899
|
|
4813
4900
|
|
4901
|
+
# class Dispatcher(abc.ABC):
|
4902
|
+
# pass
|
4903
|
+
#
|
4904
|
+
#
|
4905
|
+
# class OutputDispatcher(Dispatcher, abc.ABC):
|
4906
|
+
# pass
|
4907
|
+
#
|
4908
|
+
#
|
4909
|
+
# class InputDispatcher(Dispatcher, abc.ABC):
|
4910
|
+
# pass
|
4911
|
+
|
4912
|
+
|
4814
4913
|
@functools.total_ordering
|
4815
|
-
class
|
4914
|
+
class Process(abc.ABC):
|
4816
4915
|
@property
|
4817
4916
|
@abc.abstractmethod
|
4818
4917
|
def pid(self) -> int:
|
@@ -4831,7 +4930,7 @@ class AbstractSubprocess(abc.ABC):
|
|
4831
4930
|
|
4832
4931
|
@property
|
4833
4932
|
@abc.abstractmethod
|
4834
|
-
def context(self) ->
|
4933
|
+
def context(self) -> ServerContext:
|
4835
4934
|
raise NotImplementedError
|
4836
4935
|
|
4837
4936
|
@abc.abstractmethod
|
@@ -4867,12 +4966,12 @@ class AbstractSubprocess(abc.ABC):
|
|
4867
4966
|
raise NotImplementedError
|
4868
4967
|
|
4869
4968
|
@abc.abstractmethod
|
4870
|
-
def get_dispatchers(self) -> ta.Mapping[int, ta.Any]: #
|
4969
|
+
def get_dispatchers(self) -> ta.Mapping[int, ta.Any]: # Dispatcher]:
|
4871
4970
|
raise NotImplementedError
|
4872
4971
|
|
4873
4972
|
|
4874
4973
|
@functools.total_ordering
|
4875
|
-
class
|
4974
|
+
class ProcessGroup(abc.ABC):
|
4876
4975
|
@property
|
4877
4976
|
@abc.abstractmethod
|
4878
4977
|
def config(self) -> ProcessGroupConfig:
|
@@ -4884,12 +4983,48 @@ class AbstractProcessGroup(abc.ABC):
|
|
4884
4983
|
def __eq__(self, other):
|
4885
4984
|
return self.config.priority == other.config.priority
|
4886
4985
|
|
4986
|
+
@abc.abstractmethod
|
4987
|
+
def transition(self) -> None:
|
4988
|
+
raise NotImplementedError
|
4989
|
+
|
4990
|
+
@abc.abstractmethod
|
4991
|
+
def stop_all(self) -> None:
|
4992
|
+
raise NotImplementedError
|
4993
|
+
|
4994
|
+
@property
|
4995
|
+
@abc.abstractmethod
|
4996
|
+
def name(self) -> str:
|
4997
|
+
raise NotImplementedError
|
4998
|
+
|
4999
|
+
@abc.abstractmethod
|
5000
|
+
def before_remove(self) -> None:
|
5001
|
+
raise NotImplementedError
|
5002
|
+
|
5003
|
+
@abc.abstractmethod
|
5004
|
+
def get_dispatchers(self) -> ta.Mapping[int, ta.Any]: # Dispatcher]:
|
5005
|
+
raise NotImplementedError
|
5006
|
+
|
5007
|
+
@abc.abstractmethod
|
5008
|
+
def reopen_logs(self) -> None:
|
5009
|
+
raise NotImplementedError
|
5010
|
+
|
5011
|
+
@abc.abstractmethod
|
5012
|
+
def get_unstopped_processes(self) -> ta.List[Process]:
|
5013
|
+
raise NotImplementedError
|
5014
|
+
|
5015
|
+
@abc.abstractmethod
|
5016
|
+
def after_setuid(self) -> None:
|
5017
|
+
raise NotImplementedError
|
5018
|
+
|
4887
5019
|
|
4888
5020
|
########################################
|
4889
5021
|
# ../context.py
|
4890
5022
|
|
4891
5023
|
|
4892
|
-
|
5024
|
+
ServerEpoch = ta.NewType('ServerEpoch', int)
|
5025
|
+
|
5026
|
+
|
5027
|
+
class ServerContextImpl(ServerContext):
|
4893
5028
|
def __init__(
|
4894
5029
|
self,
|
4895
5030
|
config: ServerConfig,
|
@@ -4903,7 +5038,7 @@ class ServerContext(AbstractServerContext):
|
|
4903
5038
|
self._poller = poller
|
4904
5039
|
self._epoch = epoch
|
4905
5040
|
|
4906
|
-
self._pid_history: ta.Dict[int,
|
5041
|
+
self._pid_history: ta.Dict[int, Process] = {}
|
4907
5042
|
self._state: SupervisorState = SupervisorState.RUNNING
|
4908
5043
|
|
4909
5044
|
if config.user is not None:
|
@@ -4936,7 +5071,7 @@ class ServerContext(AbstractServerContext):
|
|
4936
5071
|
self._state = state
|
4937
5072
|
|
4938
5073
|
@property
|
4939
|
-
def pid_history(self) -> ta.Dict[int,
|
5074
|
+
def pid_history(self) -> ta.Dict[int, Process]:
|
4940
5075
|
return self._pid_history
|
4941
5076
|
|
4942
5077
|
@property
|
@@ -5283,7 +5418,7 @@ def check_execv_args(filename, argv, st) -> None:
|
|
5283
5418
|
class Dispatcher(abc.ABC):
|
5284
5419
|
def __init__(
|
5285
5420
|
self,
|
5286
|
-
process:
|
5421
|
+
process: Process,
|
5287
5422
|
channel: str,
|
5288
5423
|
fd: int,
|
5289
5424
|
*,
|
@@ -5302,7 +5437,7 @@ class Dispatcher(abc.ABC):
|
|
5302
5437
|
return f'<{self.__class__.__name__} at {id(self)} for {self._process} ({self._channel})>'
|
5303
5438
|
|
5304
5439
|
@property
|
5305
|
-
def process(self) ->
|
5440
|
+
def process(self) -> Process:
|
5306
5441
|
return self._process
|
5307
5442
|
|
5308
5443
|
@property
|
@@ -5357,7 +5492,7 @@ class OutputDispatcher(Dispatcher):
|
|
5357
5492
|
|
5358
5493
|
def __init__(
|
5359
5494
|
self,
|
5360
|
-
process:
|
5495
|
+
process: Process,
|
5361
5496
|
event_type: ta.Type[ProcessCommunicationEvent],
|
5362
5497
|
fd: int,
|
5363
5498
|
**kwargs: ta.Any,
|
@@ -5566,7 +5701,7 @@ class OutputDispatcher(Dispatcher):
|
|
5566
5701
|
class InputDispatcher(Dispatcher):
|
5567
5702
|
def __init__(
|
5568
5703
|
self,
|
5569
|
-
process:
|
5704
|
+
process: Process,
|
5570
5705
|
channel: str,
|
5571
5706
|
fd: int,
|
5572
5707
|
**kwargs: ta.Any,
|
@@ -5615,31 +5750,26 @@ class InputDispatcher(Dispatcher):
|
|
5615
5750
|
##
|
5616
5751
|
|
5617
5752
|
|
5618
|
-
|
5619
|
-
class SubprocessFactory:
|
5620
|
-
fn: ta.Callable[[ProcessConfig, AbstractProcessGroup], AbstractSubprocess]
|
5753
|
+
ProcessFactory = ta.NewType('ProcessFactory', Func[Process]) # (config: ProcessConfig, group: ProcessGroup)
|
5621
5754
|
|
5622
|
-
def __call__(self, config: ProcessConfig, group: AbstractProcessGroup) -> AbstractSubprocess:
|
5623
|
-
return self.fn(config, group)
|
5624
5755
|
|
5625
|
-
|
5626
|
-
class ProcessGroup(AbstractProcessGroup):
|
5756
|
+
class ProcessGroupImpl(ProcessGroup):
|
5627
5757
|
def __init__(
|
5628
5758
|
self,
|
5629
5759
|
config: ProcessGroupConfig,
|
5630
5760
|
context: ServerContext,
|
5631
5761
|
*,
|
5632
|
-
|
5762
|
+
process_factory: ProcessFactory,
|
5633
5763
|
):
|
5634
5764
|
super().__init__()
|
5635
5765
|
|
5636
5766
|
self._config = config
|
5637
5767
|
self._context = context
|
5638
|
-
self.
|
5768
|
+
self._process_factory = process_factory
|
5639
5769
|
|
5640
5770
|
self._processes = {}
|
5641
5771
|
for pconfig in self._config.processes or []:
|
5642
|
-
process = self.
|
5772
|
+
process = self._process_factory(pconfig, self)
|
5643
5773
|
self._processes[pconfig.name] = process
|
5644
5774
|
|
5645
5775
|
@property
|
@@ -5651,7 +5781,7 @@ class ProcessGroup(AbstractProcessGroup):
|
|
5651
5781
|
return self._config.name
|
5652
5782
|
|
5653
5783
|
@property
|
5654
|
-
def context(self) ->
|
5784
|
+
def context(self) -> ServerContext:
|
5655
5785
|
return self._context
|
5656
5786
|
|
5657
5787
|
def __repr__(self):
|
@@ -5686,7 +5816,7 @@ class ProcessGroup(AbstractProcessGroup):
|
|
5686
5816
|
# BACKOFF -> FATAL
|
5687
5817
|
proc.give_up()
|
5688
5818
|
|
5689
|
-
def get_unstopped_processes(self) -> ta.List[
|
5819
|
+
def get_unstopped_processes(self) -> ta.List[Process]:
|
5690
5820
|
return [x for x in self._processes.values() if not x.get_state().stopped]
|
5691
5821
|
|
5692
5822
|
def get_dispatchers(self) -> ta.Dict[int, Dispatcher]:
|
@@ -5763,18 +5893,21 @@ class ProcessGroups:
|
|
5763
5893
|
# ../process.py
|
5764
5894
|
|
5765
5895
|
|
5896
|
+
InheritedFds = ta.NewType('InheritedFds', ta.FrozenSet[int])
|
5897
|
+
|
5898
|
+
|
5766
5899
|
##
|
5767
5900
|
|
5768
5901
|
|
5769
|
-
class
|
5902
|
+
class ProcessImpl(Process):
|
5770
5903
|
"""A class to manage a subprocess."""
|
5771
5904
|
|
5772
5905
|
def __init__(
|
5773
5906
|
self,
|
5774
5907
|
config: ProcessConfig,
|
5775
|
-
group:
|
5908
|
+
group: ProcessGroup,
|
5776
5909
|
*,
|
5777
|
-
context:
|
5910
|
+
context: ServerContext,
|
5778
5911
|
event_callbacks: EventCallbacks,
|
5779
5912
|
|
5780
5913
|
inherited_fds: ta.Optional[InheritedFds] = None,
|
@@ -5813,7 +5946,7 @@ class Subprocess(AbstractSubprocess):
|
|
5813
5946
|
return self._pid
|
5814
5947
|
|
5815
5948
|
@property
|
5816
|
-
def group(self) ->
|
5949
|
+
def group(self) -> ProcessGroup:
|
5817
5950
|
return self._group
|
5818
5951
|
|
5819
5952
|
@property
|
@@ -5821,7 +5954,7 @@ class Subprocess(AbstractSubprocess):
|
|
5821
5954
|
return self._config
|
5822
5955
|
|
5823
5956
|
@property
|
5824
|
-
def context(self) ->
|
5957
|
+
def context(self) -> ServerContext:
|
5825
5958
|
return self._context
|
5826
5959
|
|
5827
5960
|
@property
|
@@ -6468,7 +6601,7 @@ class SignalHandler:
|
|
6468
6601
|
def __init__(
|
6469
6602
|
self,
|
6470
6603
|
*,
|
6471
|
-
context:
|
6604
|
+
context: ServerContextImpl,
|
6472
6605
|
signal_receiver: SignalReceiver,
|
6473
6606
|
process_groups: ProcessGroups,
|
6474
6607
|
) -> None:
|
@@ -6520,19 +6653,14 @@ class SignalHandler:
|
|
6520
6653
|
##
|
6521
6654
|
|
6522
6655
|
|
6523
|
-
|
6524
|
-
class ProcessGroupFactory:
|
6525
|
-
fn: ta.Callable[[ProcessGroupConfig], ProcessGroup]
|
6526
|
-
|
6527
|
-
def __call__(self, config: ProcessGroupConfig) -> ProcessGroup:
|
6528
|
-
return self.fn(config)
|
6656
|
+
ProcessGroupFactory = ta.NewType('ProcessGroupFactory', Func[ProcessGroup]) # (config: ProcessGroupConfig)
|
6529
6657
|
|
6530
6658
|
|
6531
6659
|
class Supervisor:
|
6532
6660
|
def __init__(
|
6533
6661
|
self,
|
6534
6662
|
*,
|
6535
|
-
context:
|
6663
|
+
context: ServerContextImpl,
|
6536
6664
|
poller: Poller,
|
6537
6665
|
process_groups: ProcessGroups,
|
6538
6666
|
signal_handler: SignalHandler,
|
@@ -6556,7 +6684,7 @@ class Supervisor:
|
|
6556
6684
|
#
|
6557
6685
|
|
6558
6686
|
@property
|
6559
|
-
def context(self) ->
|
6687
|
+
def context(self) -> ServerContextImpl:
|
6560
6688
|
return self._context
|
6561
6689
|
|
6562
6690
|
def get_state(self) -> SupervisorState:
|
@@ -6603,16 +6731,16 @@ class Supervisor:
|
|
6603
6731
|
return True
|
6604
6732
|
|
6605
6733
|
def get_process_map(self) -> ta.Dict[int, Dispatcher]:
|
6606
|
-
process_map = {}
|
6734
|
+
process_map: ta.Dict[int, Dispatcher] = {}
|
6607
6735
|
for group in self._process_groups:
|
6608
6736
|
process_map.update(group.get_dispatchers())
|
6609
6737
|
return process_map
|
6610
6738
|
|
6611
|
-
def shutdown_report(self) -> ta.List[
|
6612
|
-
unstopped: ta.List[
|
6739
|
+
def shutdown_report(self) -> ta.List[Process]:
|
6740
|
+
unstopped: ta.List[Process] = []
|
6613
6741
|
|
6614
6742
|
for group in self._process_groups:
|
6615
|
-
unstopped.extend(group.get_unstopped_processes())
|
6743
|
+
unstopped.extend(group.get_unstopped_processes())
|
6616
6744
|
|
6617
6745
|
if unstopped:
|
6618
6746
|
# throttle 'waiting for x to die' reports
|
@@ -6840,8 +6968,8 @@ def bind_server(
|
|
6840
6968
|
|
6841
6969
|
inj.bind(get_poller_impl(), key=Poller, singleton=True),
|
6842
6970
|
|
6843
|
-
inj.bind(
|
6844
|
-
inj.bind(
|
6971
|
+
inj.bind(ServerContextImpl, singleton=True),
|
6972
|
+
inj.bind(ServerContext, to_key=ServerContextImpl),
|
6845
6973
|
|
6846
6974
|
inj.bind(EventCallbacks, singleton=True),
|
6847
6975
|
|
@@ -6850,21 +6978,10 @@ def bind_server(
|
|
6850
6978
|
inj.bind(SignalHandler, singleton=True),
|
6851
6979
|
inj.bind(ProcessGroups, singleton=True),
|
6852
6980
|
inj.bind(Supervisor, singleton=True),
|
6853
|
-
]
|
6854
6981
|
|
6855
|
-
|
6856
|
-
|
6857
|
-
|
6858
|
-
def inner(group_config: ProcessGroupConfig) -> ProcessGroup:
|
6859
|
-
return injector.inject(functools.partial(ProcessGroup, group_config))
|
6860
|
-
return ProcessGroupFactory(inner)
|
6861
|
-
lst.append(inj.bind(make_process_group_factory))
|
6862
|
-
|
6863
|
-
def make_subprocess_factory(injector: Injector) -> SubprocessFactory:
|
6864
|
-
def inner(process_config: ProcessConfig, group: AbstractProcessGroup) -> AbstractSubprocess:
|
6865
|
-
return injector.inject(functools.partial(Subprocess, process_config, group))
|
6866
|
-
return SubprocessFactory(inner)
|
6867
|
-
lst.append(inj.bind(make_subprocess_factory))
|
6982
|
+
inj.bind_factory(ProcessGroupFactory, ProcessGroupImpl),
|
6983
|
+
inj.bind_factory(ProcessFactory, ProcessImpl),
|
6984
|
+
]
|
6868
6985
|
|
6869
6986
|
#
|
6870
6987
|
|
@@ -6933,7 +7050,7 @@ def main(
|
|
6933
7050
|
inherited_fds=inherited_fds,
|
6934
7051
|
))
|
6935
7052
|
|
6936
|
-
context = injector[
|
7053
|
+
context = injector[ServerContextImpl]
|
6937
7054
|
supervisor = injector[Supervisor]
|
6938
7055
|
|
6939
7056
|
try:
|