aspyx-service 0.10.3__tar.gz → 0.10.5__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.

Potentially problematic release.


This version of aspyx-service might be problematic. Click here for more details.

Files changed (36) hide show
  1. {aspyx_service-0.10.3 → aspyx_service-0.10.5}/PKG-INFO +56 -12
  2. {aspyx_service-0.10.3 → aspyx_service-0.10.5}/README.md +54 -10
  3. aspyx_service-0.10.5/performance-test/client.py +155 -0
  4. aspyx_service-0.10.5/performance-test/main.py +34 -0
  5. {aspyx_service-0.10.3/performance_tests → aspyx_service-0.10.5/performance-test}/performance-test.py +92 -12
  6. aspyx_service-0.10.5/performance-test/readme.txt +1 -0
  7. aspyx_service-0.10.5/performance-test/server.py +168 -0
  8. aspyx_service-0.10.5/performance-test/start_server_8000.sh +3 -0
  9. aspyx_service-0.10.5/performance-test/start_server_8001.sh +3 -0
  10. {aspyx_service-0.10.3 → aspyx_service-0.10.5}/pyproject.toml +12 -2
  11. {aspyx_service-0.10.3 → aspyx_service-0.10.5}/src/aspyx_service/__init__.py +30 -5
  12. aspyx_service-0.10.5/src/aspyx_service/authorization.py +126 -0
  13. aspyx_service-0.10.5/src/aspyx_service/channels.py +473 -0
  14. {aspyx_service-0.10.3 → aspyx_service-0.10.5}/src/aspyx_service/healthcheck.py +1 -1
  15. {aspyx_service-0.10.3 → aspyx_service-0.10.5}/src/aspyx_service/registries.py +5 -5
  16. {aspyx_service-0.10.3 → aspyx_service-0.10.5}/src/aspyx_service/restchannel.py +13 -20
  17. aspyx_service-0.10.5/src/aspyx_service/server.py +360 -0
  18. {aspyx_service-0.10.3 → aspyx_service-0.10.5}/src/aspyx_service/service.py +47 -12
  19. aspyx_service-0.10.5/src/aspyx_service/session.py +136 -0
  20. aspyx_service-0.10.5/tests/__init__.py +0 -0
  21. {aspyx_service-0.10.3 → aspyx_service-0.10.5}/tests/common.py +176 -34
  22. aspyx_service-0.10.5/tests/config.yaml +16 -0
  23. aspyx_service-0.10.5/tests/test_async_service.py +58 -0
  24. aspyx_service-0.10.5/tests/test_healthcheck.py +51 -0
  25. aspyx_service-0.10.5/tests/test_jwt.py +422 -0
  26. {aspyx_service-0.10.3 → aspyx_service-0.10.5}/tests/test_serialization.py +9 -7
  27. aspyx_service-0.10.5/tests/test_service.py +80 -0
  28. aspyx_service-0.10.3/src/aspyx_service/channels.py +0 -282
  29. aspyx_service-0.10.3/src/aspyx_service/serialization.py +0 -137
  30. aspyx_service-0.10.3/src/aspyx_service/server.py +0 -228
  31. aspyx_service-0.10.3/tests/test_async_service.py +0 -56
  32. aspyx_service-0.10.3/tests/test_service.py +0 -82
  33. {aspyx_service-0.10.3 → aspyx_service-0.10.5}/.gitignore +0 -0
  34. {aspyx_service-0.10.3 → aspyx_service-0.10.5}/LICENSE +0 -0
  35. {aspyx_service-0.10.3/tests → aspyx_service-0.10.5/performance-test}/__init__.py +0 -0
  36. {aspyx_service-0.10.3/tests → aspyx_service-0.10.5/performance-test}/config.yaml +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: aspyx_service
3
- Version: 0.10.3
3
+ Version: 0.10.5
4
4
  Summary: Aspyx Service framework
5
5
  Author-email: Andreas Ernst <andreas.ernst7@gmail.com>
6
6
  License: MIT License
@@ -26,7 +26,7 @@ License: MIT License
26
26
  SOFTWARE.
27
27
  License-File: LICENSE
28
28
  Requires-Python: >=3.9
29
- Requires-Dist: aspyx>=1.5.1
29
+ Requires-Dist: aspyx>=1.6.0
30
30
  Requires-Dist: fastapi~=0.115.13
31
31
  Requires-Dist: httpx~=0.28.1
32
32
  Requires-Dist: msgpack~=1.1.1
@@ -60,6 +60,8 @@ Description-Content-Type: text/markdown
60
60
  - [Rest Calls](#rest-calls)
61
61
  - [Intercepting calls](#intercepting-calls)
62
62
  - [FastAPI server](#fastapi-server)
63
+ - [Session](#session)
64
+ - [Authorization](#authorization)
63
65
  - [Implementing Channels](#implementing-channels)
64
66
  - [Version History](#version-history)
65
67
 
@@ -107,18 +109,20 @@ class TestComponent(Component):
107
109
  After booting the DI infrastructure with a main module we could already call a service:
108
110
 
109
111
  **Example**:
112
+
110
113
  ```python
111
114
  @module(imports=[ServiceModule])
112
115
  class Module:
113
116
  def __init__(self):
114
117
  pass
115
-
118
+
116
119
  @create()
117
120
  def create_registry(self) -> ConsulComponentRegistry:
118
- return ConsulComponentRegistry(Server.port, Consul(host="localhost", port=8500)) # a consul based registry!
121
+ return ConsulComponentRegistry(Server.port, Consul(host="localhost", port=8500)) # a consul based registry!
122
+
119
123
 
120
124
  environment = Environment(Module)
121
- service_manager = environment.get(ServiceManager)
125
+ service_manager = environment.read(ServiceManager)
122
126
 
123
127
  service = service_manager.get_service(TestService)
124
128
 
@@ -166,10 +170,24 @@ environment = server.boot(Module)
166
170
  Of course, service can also be called locally. In case of multiple possible channels, a keyword argument is used to
167
171
  determine a specific channel. As a local channel has the name "local", the appropriate call is:
168
172
 
173
+ **Example**:
174
+
169
175
  ```python
170
176
  service = service_manager.get_service(TestService, preferred_channel="local")
171
177
  ```
172
178
 
179
+ The default can be set globally with the method `set_preferred_channel(channel: str)`
180
+
181
+ Injecting services is also possible via the decorator `@inject_service(preferred_channel=""")`
182
+
183
+ **Example**:
184
+
185
+ ```python
186
+ @inject_service()
187
+ def set_service(self, service: TestService)
188
+ self.service = service
189
+ ```
190
+
173
191
  ## Features
174
192
 
175
193
  The library offers:
@@ -185,6 +203,14 @@ The library offers:
185
203
  As well as the DI and AOP core, all mechanisms are heavily optimized.
186
204
  A simple benchmark resulted in message roundtrips in significanlty under a ms per call.
187
205
 
206
+ ## Installation
207
+
208
+ Just install from PyPI with
209
+
210
+ `pip install aspyx-service`
211
+
212
+ The library is tested with all Python version >= 3.9
213
+
188
214
  Let's see some details
189
215
 
190
216
  ## Service and Component declaration
@@ -352,12 +378,14 @@ Channels implement the possible transport layer protocols. In the sense of a dyn
352
378
  Several channels are implemented:
353
379
 
354
380
  - `dispatch-json`
355
- channel that dispatches generic `Request` objects via a `invoke` POST-call
381
+ channel that posts generic `Request` objects via a `invoke` POST-call
356
382
  - `dispatch-msgpack`
357
- channel that dispatches generic `Request` objects via a `invoke` POST-call after packing the json with msgpack
383
+ channel that posts generic `Request` objects via a `invoke` POST-call after packing the json with msgpack
358
384
  - `rest`
359
385
  channel that executes regular rest-calls as defined by a couple of decorators.
360
386
 
387
+ The `dispatch`channels have the big advantage, that you don`t have to deal with additional http decorators!
388
+
361
389
  All channels react on changed URLs as provided by the component registry.
362
390
 
363
391
  A so called `URLSelector` is used internally to provide URLs for every single call. Two subclasses exist that offer a different logic
@@ -465,23 +493,39 @@ class ChannelAdvice:
465
493
 
466
494
  ## FastAPI server
467
495
 
468
- In order to expose components via HTTP, the corresponding infrastructure in form of a FastAPI server needs to be setup.
496
+ The required - `FastAPI` - infrastructure to expose those services requires:
469
497
 
498
+ - a `FastAPI` instance
499
+ - an injectable `FastAPIServer`
500
+ - and a final `boot` call with the root module, which will return an `Environment`
470
501
 
471
502
  ```python
472
- @module()
473
- class Module():
503
+ fast_api = FastAPI() # so you can run it with uvivorn from command-line
504
+
505
+ @module(imports=[ServiceModule])
506
+ class Module:
474
507
  def __init__(self):
475
508
  pass
509
+
510
+ @create()
511
+ def create_server(self, service_manager: ServiceManager, component_registry: ComponentRegistry) -> FastAPIServer:
512
+ return FastAPIServer(fastapi, service_manager, component_registry)
476
513
 
477
- server = FastAPIServer(host="0.0.0.0", port=8000)
478
514
 
479
- environment = server.boot(Module) # will start the http server
515
+ environment = FastAPIServer.boot(Moudle, host="0.0.0.0", port=8000)
480
516
  ```
481
517
 
482
518
  This setup will also expose all service interfaces decorated with the corresponding http decorators!
483
519
  No need to add any FastAPI decorators, since the mapping is already done internally!
484
520
 
521
+ ## Session
522
+
523
+ TODO
524
+
525
+ ## Authorization
526
+
527
+ TODO
528
+
485
529
  ## Implementing Channels
486
530
 
487
531
  To implement a new channel, you only need to derive from one of the possible base classes ( `Channel` or `HTTPXChannel` that already has a `httpx` client)
@@ -24,6 +24,8 @@
24
24
  - [Rest Calls](#rest-calls)
25
25
  - [Intercepting calls](#intercepting-calls)
26
26
  - [FastAPI server](#fastapi-server)
27
+ - [Session](#session)
28
+ - [Authorization](#authorization)
27
29
  - [Implementing Channels](#implementing-channels)
28
30
  - [Version History](#version-history)
29
31
 
@@ -71,18 +73,20 @@ class TestComponent(Component):
71
73
  After booting the DI infrastructure with a main module we could already call a service:
72
74
 
73
75
  **Example**:
76
+
74
77
  ```python
75
78
  @module(imports=[ServiceModule])
76
79
  class Module:
77
80
  def __init__(self):
78
81
  pass
79
-
82
+
80
83
  @create()
81
84
  def create_registry(self) -> ConsulComponentRegistry:
82
- return ConsulComponentRegistry(Server.port, Consul(host="localhost", port=8500)) # a consul based registry!
85
+ return ConsulComponentRegistry(Server.port, Consul(host="localhost", port=8500)) # a consul based registry!
86
+
83
87
 
84
88
  environment = Environment(Module)
85
- service_manager = environment.get(ServiceManager)
89
+ service_manager = environment.read(ServiceManager)
86
90
 
87
91
  service = service_manager.get_service(TestService)
88
92
 
@@ -130,10 +134,24 @@ environment = server.boot(Module)
130
134
  Of course, service can also be called locally. In case of multiple possible channels, a keyword argument is used to
131
135
  determine a specific channel. As a local channel has the name "local", the appropriate call is:
132
136
 
137
+ **Example**:
138
+
133
139
  ```python
134
140
  service = service_manager.get_service(TestService, preferred_channel="local")
135
141
  ```
136
142
 
143
+ The default can be set globally with the method `set_preferred_channel(channel: str)`
144
+
145
+ Injecting services is also possible via the decorator `@inject_service(preferred_channel=""")`
146
+
147
+ **Example**:
148
+
149
+ ```python
150
+ @inject_service()
151
+ def set_service(self, service: TestService)
152
+ self.service = service
153
+ ```
154
+
137
155
  ## Features
138
156
 
139
157
  The library offers:
@@ -149,6 +167,14 @@ The library offers:
149
167
  As well as the DI and AOP core, all mechanisms are heavily optimized.
150
168
  A simple benchmark resulted in message roundtrips in significanlty under a ms per call.
151
169
 
170
+ ## Installation
171
+
172
+ Just install from PyPI with
173
+
174
+ `pip install aspyx-service`
175
+
176
+ The library is tested with all Python version >= 3.9
177
+
152
178
  Let's see some details
153
179
 
154
180
  ## Service and Component declaration
@@ -316,12 +342,14 @@ Channels implement the possible transport layer protocols. In the sense of a dyn
316
342
  Several channels are implemented:
317
343
 
318
344
  - `dispatch-json`
319
- channel that dispatches generic `Request` objects via a `invoke` POST-call
345
+ channel that posts generic `Request` objects via a `invoke` POST-call
320
346
  - `dispatch-msgpack`
321
- channel that dispatches generic `Request` objects via a `invoke` POST-call after packing the json with msgpack
347
+ channel that posts generic `Request` objects via a `invoke` POST-call after packing the json with msgpack
322
348
  - `rest`
323
349
  channel that executes regular rest-calls as defined by a couple of decorators.
324
350
 
351
+ The `dispatch`channels have the big advantage, that you don`t have to deal with additional http decorators!
352
+
325
353
  All channels react on changed URLs as provided by the component registry.
326
354
 
327
355
  A so called `URLSelector` is used internally to provide URLs for every single call. Two subclasses exist that offer a different logic
@@ -429,23 +457,39 @@ class ChannelAdvice:
429
457
 
430
458
  ## FastAPI server
431
459
 
432
- In order to expose components via HTTP, the corresponding infrastructure in form of a FastAPI server needs to be setup.
460
+ The required - `FastAPI` - infrastructure to expose those services requires:
433
461
 
462
+ - a `FastAPI` instance
463
+ - an injectable `FastAPIServer`
464
+ - and a final `boot` call with the root module, which will return an `Environment`
434
465
 
435
466
  ```python
436
- @module()
437
- class Module():
467
+ fast_api = FastAPI() # so you can run it with uvivorn from command-line
468
+
469
+ @module(imports=[ServiceModule])
470
+ class Module:
438
471
  def __init__(self):
439
472
  pass
473
+
474
+ @create()
475
+ def create_server(self, service_manager: ServiceManager, component_registry: ComponentRegistry) -> FastAPIServer:
476
+ return FastAPIServer(fastapi, service_manager, component_registry)
440
477
 
441
- server = FastAPIServer(host="0.0.0.0", port=8000)
442
478
 
443
- environment = server.boot(Module) # will start the http server
479
+ environment = FastAPIServer.boot(Moudle, host="0.0.0.0", port=8000)
444
480
  ```
445
481
 
446
482
  This setup will also expose all service interfaces decorated with the corresponding http decorators!
447
483
  No need to add any FastAPI decorators, since the mapping is already done internally!
448
484
 
485
+ ## Session
486
+
487
+ TODO
488
+
489
+ ## Authorization
490
+
491
+ TODO
492
+
449
493
  ## Implementing Channels
450
494
 
451
495
  To implement a new channel, you only need to derive from one of the possible base classes ( `Channel` or `HTTPXChannel` that already has a `httpx` client)
@@ -0,0 +1,155 @@
1
+ """
2
+ Tests
3
+ """
4
+
5
+ from abc import abstractmethod
6
+ from dataclasses import dataclass
7
+
8
+ from pydantic import BaseModel
9
+
10
+ from aspyx_service import ServiceModule, delete, post, put, get, rest, Body
11
+ from aspyx_service.service import component, Component, Service, service
12
+
13
+ from aspyx.di import module
14
+
15
+
16
+ class Pydantic(BaseModel):
17
+ i: int
18
+ f: float
19
+ b: bool
20
+ s: str
21
+
22
+ str0 : str
23
+ str1: str
24
+ str2: str
25
+ str3: str
26
+ str4: str
27
+ str5: str
28
+ str6: str
29
+ str7: str
30
+ str8: str
31
+ str9: str
32
+
33
+
34
+ @dataclass
35
+ class Data:
36
+ i: int
37
+ f: float
38
+ b: bool
39
+ s: str
40
+
41
+ str0: str
42
+ str1: str
43
+ str2: str
44
+ str3: str
45
+ str4: str
46
+ str5: str
47
+ str6: str
48
+ str7: str
49
+ str8: str
50
+ str9: str
51
+
52
+ class PydanticAndData(BaseModel):
53
+ p: Pydantic
54
+
55
+ @dataclass
56
+ class DataAndPydantic:
57
+ d: Data
58
+
59
+ # service
60
+
61
+ @service(name="test-service", description="cool")
62
+ class TestService(Service):
63
+ @abstractmethod
64
+ def hello(self, message: str) -> str:
65
+ pass
66
+
67
+ @abstractmethod
68
+ def throw(self, message: str) -> str:
69
+ pass
70
+
71
+ @abstractmethod
72
+ def data(self, data: Data) -> Data:
73
+ pass
74
+
75
+ @abstractmethod
76
+ def pydantic(self, data: Pydantic) -> Pydantic:
77
+ pass
78
+
79
+ @service(name="test-async-service", description="cool")
80
+ class TestAsyncService(Service):
81
+ @abstractmethod
82
+ async def hello(self, message: str) -> str:
83
+ pass
84
+
85
+ @abstractmethod
86
+ async def data(self, data: Data) -> Data:
87
+ pass
88
+
89
+ @abstractmethod
90
+ async def pydantic(self, data: Pydantic) -> Pydantic:
91
+ pass
92
+
93
+ @service(name="test-rest-service", description="cool")
94
+ @rest("/api")
95
+ class TestRestService(Service):
96
+ @abstractmethod
97
+ @get("/hello/{message}")
98
+ def get(self, message: str) -> str:
99
+ pass
100
+
101
+ @put("/hello/{message}")
102
+ def put(self, message: str) -> str:
103
+ pass
104
+
105
+ @post("/hello/{message}")
106
+ def post_pydantic(self, message: str, data: Body(Pydantic)) -> Pydantic:
107
+ pass
108
+
109
+ @post("/hello/{message}")
110
+ def post_data(self, message: str, data: Body(Data)) -> Data:
111
+ pass
112
+
113
+ @delete("/hello/{message}")
114
+ def delete(self, message: str) -> str:
115
+ pass
116
+
117
+ @service(name="test-async-rest-service", description="cool")
118
+ @rest("/async-api")
119
+ class TestAsyncRestService(Service):
120
+ @abstractmethod
121
+ @get("/hello/{message}")
122
+ async def get(self, message: str) -> str:
123
+ pass
124
+
125
+ @put("/hello/{message}")
126
+ async def put(self, message: str) -> str:
127
+ pass
128
+
129
+ @post("/hello/{message}")
130
+ async def post_pydantic(self, message: str, data: Body(Pydantic)) -> Pydantic:
131
+ pass
132
+
133
+ @post("/hello/{message}")
134
+ async def post_data(self, message: str, data: Body(Data)) -> Data:
135
+ pass
136
+
137
+ @delete("/hello/{message}")
138
+ async def delete(self, message: str) -> str:
139
+ pass
140
+
141
+ @component(services =[
142
+ TestService,
143
+ TestAsyncService,
144
+ TestRestService,
145
+ TestAsyncRestService
146
+ ])
147
+ class TestComponent(Component): # pylint: disable=abstract-method
148
+ pass
149
+
150
+ # module
151
+
152
+ @module(imports=[ServiceModule])
153
+ class ClientModule:
154
+ def __init__(self):
155
+ pass
@@ -0,0 +1,34 @@
1
+ """
2
+ the server hosting the test services
3
+ """
4
+ import logging
5
+ import os
6
+
7
+ from fastapi import FastAPI
8
+
9
+ from aspyx_service import FastAPIServer, RequestContext
10
+ from server import ServerModule
11
+ from aspyx.util import Logger
12
+
13
+
14
+ Logger.configure(default_level=logging.DEBUG, levels={
15
+ "httpx": logging.ERROR,
16
+ "aspyx.di": logging.ERROR,
17
+ "aspyx.di.aop": logging.ERROR,
18
+ "aspyx.service": logging.ERROR
19
+ })
20
+
21
+ PORT = int(os.getenv("FAST_API_PORT", "8000"))
22
+
23
+ app = FastAPI()
24
+
25
+ app.add_middleware(RequestContext)
26
+ #app.add_middleware(TokenContextMiddleware)
27
+
28
+ ServerModule.fastapi = app
29
+
30
+ FastAPIServer.boot(ServerModule, host="0.0.0.0", port=PORT, start_thread= False)
31
+
32
+ if __name__ == "__main__":
33
+ import uvicorn
34
+ uvicorn.run("main:app", host="0.0.0.0", port=PORT, reload=True, log_level="warning", access_log=False)
@@ -2,22 +2,97 @@
2
2
  Tests
3
3
  """
4
4
  import asyncio
5
- import logging
6
5
  import threading
7
6
  import time
7
+ import logging
8
+
9
+ from typing import Callable, TypeVar, Type, Awaitable, Any, Dict, cast
10
+
11
+ from consul import Consul
12
+
13
+ from aspyx_service import ConsulComponentRegistry, SessionManager
14
+
15
+ from aspyx.di import module, Environment, create
16
+ from aspyx.di.aop import advice, around, methods, Invocation
17
+ from aspyx.util import Logger
18
+
19
+
20
+ from aspyx_service.service import ServiceManager, ComponentRegistry, Channel
21
+
22
+ Logger.configure(default_level=logging.INFO, levels={
23
+ "httpx": logging.CRITICAL,
24
+ "aspyx.di": logging.INFO,
25
+ "aspyx.di.aop": logging.INFO,
26
+ "aspyx.service": logging.INFO
27
+ })
28
+
29
+ from client import TestService, TestRestService, Pydantic, Data, TestAsyncRestService, TestAsyncService, ClientModule
30
+
31
+ # main
32
+
33
+ @advice
34
+ class ChannelAdvice:
35
+ def __init__(self):
36
+ pass
37
+
38
+ @around(methods().named("customize").of_type(Channel))
39
+ def customize_channel(self, invocation: Invocation):
40
+ channel = cast(Channel, invocation.args[0])
8
41
 
9
- from typing import Callable, TypeVar, Type, Awaitable, Any
42
+ channel.select_round_robin() # or select_first_url()
10
43
 
11
- from packages.aspyx_service.tests.common import service_manager, TestService, TestRestService, Pydantic, Data, \
12
- TestAsyncRestService, TestAsyncService
13
- from packages.aspyx_service.tests.test_async_service import data
44
+ return invocation.proceed()
45
+
46
+ @module(imports=[ClientModule])
47
+ class TestModule:
48
+ def __init__(self):
49
+ pass
50
+
51
+ @create()
52
+ def create_session_storage(self) -> SessionManager.Storage:
53
+ return SessionManager.InMemoryStorage(max_size=1000, ttl=3600)
54
+
55
+ @create()
56
+ def create_registry(self) -> ComponentRegistry:
57
+ return ConsulComponentRegistry(port=8000, consul=Consul(host="localhost", port=8500))
58
+
59
+ def boot() -> ServiceManager:
60
+ environment = Environment(TestModule)
61
+
62
+ service_manager = environment.get(ServiceManager)
63
+
64
+ return service_manager
14
65
 
15
66
  T = TypeVar("T")
16
67
 
17
68
  # main
18
69
 
19
- pydantic = Pydantic(i=1, f=1.0, b=True, s="s")
20
- data = Data(i=1, f=1.0, b=True, s="s")
70
+ lorem_ipsum = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua"
71
+
72
+ pydantic = Pydantic(i=1, f=1.0, b=True, s="s",
73
+ str0=lorem_ipsum,
74
+ str1=lorem_ipsum,
75
+ str2=lorem_ipsum,
76
+ str3=lorem_ipsum,
77
+ str4=lorem_ipsum,
78
+ str5=lorem_ipsum,
79
+ str6=lorem_ipsum,
80
+ str7=lorem_ipsum,
81
+ str8=lorem_ipsum,
82
+ str9=lorem_ipsum
83
+ )
84
+ data = Data(i=1, f=1.0, b=True, s="s",
85
+ str0=lorem_ipsum,
86
+ str1=lorem_ipsum,
87
+ str2=lorem_ipsum,
88
+ str3=lorem_ipsum,
89
+ str4=lorem_ipsum,
90
+ str5=lorem_ipsum,
91
+ str6=lorem_ipsum,
92
+ str7=lorem_ipsum,
93
+ str8=lorem_ipsum,
94
+ str9=lorem_ipsum
95
+ )
21
96
 
22
97
  def run_loops(name: str, loops: int, type: Type[T], instance: T, callable: Callable[[T], None]):
23
98
  start = time.perf_counter()
@@ -43,6 +118,8 @@ def run_threaded_async_loops(name: str, loops: int, n_threads: int, type: Type[
43
118
  threads = []
44
119
 
45
120
  def worker(thread_id: int):
121
+ #print(f"worker {thread_id} running on thread {threading.current_thread().name}")
122
+
46
123
  loop = asyncio.new_event_loop()
47
124
  asyncio.set_event_loop(loop)
48
125
 
@@ -73,6 +150,8 @@ def run_threaded_sync_loops(name: str, loops: int, n_threads: int, type: Type[T
73
150
  threads = []
74
151
 
75
152
  def worker(thread_id: int):
153
+ #print(f"worker {thread_id} running on thread {threading.current_thread().name}")
154
+
76
155
  loop = asyncio.new_event_loop()
77
156
  asyncio.set_event_loop(loop)
78
157
 
@@ -99,10 +178,13 @@ def run_threaded_sync_loops(name: str, loops: int, n_threads: int, type: Type[T
99
178
 
100
179
  print(f"{name} {loops} in {n_threads} threads: {took} ms, avg: {avg_ms}ms")
101
180
 
181
+ manager = boot()
182
+
102
183
  async def main():
184
+ print("start tests...")
185
+
103
186
  # get service manager
104
187
 
105
- manager = service_manager()
106
188
  loops = 1000
107
189
 
108
190
  # tests
@@ -131,7 +213,7 @@ async def main():
131
213
  # async
132
214
 
133
215
  await run_async_loops("async rest", loops, TestAsyncRestService, manager.get_service(TestAsyncRestService, preferred_channel="rest"),
134
- lambda service: service.get("world"))
216
+ lambda service: service.get("world"))
135
217
  await run_async_loops("async json", loops, TestAsyncService, manager.get_service(TestAsyncService, preferred_channel="dispatch-json"),
136
218
  lambda service: service.hello("world"))
137
219
  await run_async_loops("async msgpack", loops, TestAsyncService, manager.get_service(TestAsyncService, preferred_channel="dispatch-msgpack"),
@@ -166,7 +248,7 @@ async def main():
166
248
  # sync
167
249
 
168
250
  run_threaded_sync_loops("threaded sync json, 1 thread", loops, 1, TestService,
169
- manager.get_service(TestAsyncService, preferred_channel="dispatch-json"),
251
+ manager.get_service(TestService, preferred_channel="dispatch-json"),
170
252
  lambda service: service.hello("world"))
171
253
  run_threaded_sync_loops("threaded sync json, 2 thread", loops, 2, TestService,
172
254
  manager.get_service(TestService, preferred_channel="dispatch-json"),
@@ -199,7 +281,5 @@ async def main():
199
281
  manager.get_service(TestAsyncService, preferred_channel="dispatch-json"),
200
282
  lambda service: service.hello("world"))
201
283
 
202
-
203
284
  if __name__ == "__main__":
204
285
  asyncio.run(main())
205
-
@@ -0,0 +1 @@
1
+ uvicorn main:app --host 0.0.0.0 --port 8000 --workers 1 --reload --log-level warning