Skip to content

Commit 3d8afdd

Browse files
author
David Erb
committed
move client instance out of service context
1 parent 07033f7 commit 3d8afdd

File tree

3 files changed

+143
-119
lines changed

3 files changed

+143
-119
lines changed
Lines changed: 45 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import logging
2-
3-
from dls_servbase_api.datafaces.context import Context as DatafaceContext
2+
from typing import Dict
43

54
# Base class for an asyncio context
65
from dls_servbase_lib.contexts.base import Base as ContextBase
@@ -16,23 +15,34 @@
1615

1716
class Context(ContextBase):
1817
"""
19-
Asyncio context for a dls_servbase_dataface server object.
18+
Asyncio context for a servbase object.
2019
On entering, it creates the object according to the specification (a dict).
21-
If configured, it starts the server as a coroutine, thread or process.
22-
On exiting, it commands the server to shut down.
23-
24-
The enter and exit methods are exposed for use during testing.
20+
If specified, it starts the server as a coroutine, thread or process.
21+
If not a server, then it will instatiate a direct access to a servbase.
22+
On exiting, it commands the server to shut down and/or releases the direct access resources.
2523
"""
2624

2725
# ----------------------------------------------------------------------------------------
28-
def __init__(self, specification):
26+
def __init__(self, specification: Dict):
27+
"""
28+
Constructor.
29+
30+
Args:
31+
specification (Dict): specification of the servbase object to be constructed within the context.
32+
The only key in the specification that relates to the context is "start_as", which can be "coro", "thread", "process" or None.
33+
All other keys in the specification relate to creating the servbase object.
34+
"""
2935
ContextBase.__init__(self, thing_type, specification)
3036

31-
self.__api_context = None
32-
3337
# ----------------------------------------------------------------------------------------
34-
async def aenter(self):
35-
""" """
38+
async def aenter(self) -> None:
39+
"""
40+
Asyncio context entry.
41+
42+
Starts and activates service as specified.
43+
44+
Establishes the global (singleton-like) default servbase.
45+
"""
3646

3747
# Build the object according to the specification.
3848
self.server = Datafaces().build_object(self.specification())
@@ -46,16 +56,30 @@ async def aenter(self):
4656
elif self.context_specification.get("start_as") == "process":
4757
await self.server.start_process()
4858

49-
self.__api_context = DatafaceContext(self.specification())
50-
await self.__api_context.aenter()
59+
# Not running as a service?
60+
elif self.context_specification.get("start_as") == "direct":
61+
# We need to activate the tick() task.
62+
await self.server.activate()
5163

5264
# ----------------------------------------------------------------------------------------
53-
async def aexit(self):
54-
""" """
65+
async def aexit(self) -> None:
66+
"""
67+
Asyncio context exit.
5568
56-
if self.server is not None:
57-
# Put in request to shutdown the server.
58-
await self.server.client_shutdown()
69+
Stop service if one was started and releases any client resources.
70+
"""
5971

60-
if self.__api_context is not None:
61-
await self.__api_context.aexit()
72+
if self.server is not None:
73+
if self.context_specification.get("start_as") == "process":
74+
logger.info(
75+
"[DISSHU] in context exit, sending shutdown to client process"
76+
)
77+
# Put in request to shutdown the server.
78+
await self.server.client_shutdown()
79+
logger.info("[DISSHU] in context exit, sent shutdown to client process")
80+
81+
if self.context_specification.get("start_as") == "coro":
82+
await self.server.direct_shutdown()
83+
84+
if self.context_specification.get("start_as") == "direct":
85+
await self.server.deactivate()

tests/test_dataface.py

Lines changed: 71 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,9 @@
11
import logging
22

33
from dls_servbase_api.databases.constants import CookieFieldnames, Tablenames
4-
5-
# Object managing datafaces.
4+
from dls_servbase_api.datafaces.context import Context as ClientContext
65
from dls_servbase_api.datafaces.datafaces import dls_servbase_datafaces_get_default
7-
8-
# Context creator.
9-
from dls_servbase_lib.contexts.contexts import Contexts
6+
from dls_servbase_lib.datafaces.context import Context as ServerContext
107

118
# Base class for the tester.
129
from tests.base_context_tester import BaseContextTester
@@ -40,65 +37,72 @@ async def _main_coroutine(self, constants, output_directory):
4037

4138
context_configuration = await dls_servbase_multiconf.load()
4239

43-
dls_servbase_context = Contexts().build_object(context_configuration)
44-
45-
async with dls_servbase_context:
46-
dataface = dls_servbase_datafaces_get_default()
47-
48-
# Write one record.
49-
await dataface.insert(
50-
Tablenames.COOKIES,
51-
[
52-
{
53-
CookieFieldnames.UUID: "f0",
54-
CookieFieldnames.CONTENTS: "{'a': 'f000'}",
55-
}
56-
],
57-
)
58-
59-
all_sql = f"SELECT * FROM {Tablenames.COOKIES}"
60-
records = await dataface.query(all_sql)
61-
62-
assert len(records) == 1
63-
assert records[0][CookieFieldnames.UUID] == "f0"
64-
assert records[0][CookieFieldnames.CONTENTS] == "{'a': 'f000'}"
65-
66-
# ----------------------------------------------------------------
67-
# Now try a direct update.
68-
record = {
69-
CookieFieldnames.CONTENTS: "{'b': 'f1111'}",
70-
}
71-
72-
subs = ["f0"]
73-
result = await dataface.update(
74-
Tablenames.COOKIES,
75-
record,
76-
f"{CookieFieldnames.UUID} = ?",
77-
subs=subs,
78-
why="test update",
79-
)
80-
81-
assert result["count"] == 1
82-
records = await dataface.query(all_sql)
83-
84-
assert len(records) == 1
85-
assert records[0][CookieFieldnames.UUID] == "f0"
86-
assert records[0][CookieFieldnames.CONTENTS] == "{'b': 'f1111'}"
87-
88-
# ----------------------------------------------------------------
89-
# Now try a high level API update.
90-
record = {
91-
CookieFieldnames.UUID: "f0",
92-
CookieFieldnames.CONTENTS: "{'c': 'f2222'}",
93-
}
94-
95-
result = await dataface.update_cookie(
96-
record,
97-
)
98-
99-
assert result["count"] == 1
100-
records = await dataface.query(all_sql)
101-
102-
assert len(records) == 1
103-
assert records[0][CookieFieldnames.UUID] == "f0"
104-
assert records[0][CookieFieldnames.CONTENTS] == "{'c': 'f2222'}"
40+
servbase_specification = context_configuration[
41+
"dls_servbase_dataface_specification"
42+
]
43+
44+
dls_servbase_client_context = ClientContext(servbase_specification)
45+
46+
dls_servbase_server_context = ServerContext(servbase_specification)
47+
48+
async with dls_servbase_client_context:
49+
async with dls_servbase_server_context:
50+
dataface = dls_servbase_datafaces_get_default()
51+
52+
# Write one record.
53+
await dataface.insert(
54+
Tablenames.COOKIES,
55+
[
56+
{
57+
CookieFieldnames.UUID: "f0",
58+
CookieFieldnames.CONTENTS: "{'a': 'f000'}",
59+
}
60+
],
61+
)
62+
63+
all_sql = f"SELECT * FROM {Tablenames.COOKIES}"
64+
records = await dataface.query(all_sql)
65+
66+
assert len(records) == 1
67+
assert records[0][CookieFieldnames.UUID] == "f0"
68+
assert records[0][CookieFieldnames.CONTENTS] == "{'a': 'f000'}"
69+
70+
# ----------------------------------------------------------------
71+
# Now try a direct update.
72+
record = {
73+
CookieFieldnames.CONTENTS: "{'b': 'f1111'}",
74+
}
75+
76+
subs = ["f0"]
77+
result = await dataface.update(
78+
Tablenames.COOKIES,
79+
record,
80+
f"{CookieFieldnames.UUID} = ?",
81+
subs=subs,
82+
why="test update",
83+
)
84+
85+
assert result["count"] == 1
86+
records = await dataface.query(all_sql)
87+
88+
assert len(records) == 1
89+
assert records[0][CookieFieldnames.UUID] == "f0"
90+
assert records[0][CookieFieldnames.CONTENTS] == "{'b': 'f1111'}"
91+
92+
# ----------------------------------------------------------------
93+
# Now try a high level API update.
94+
record = {
95+
CookieFieldnames.UUID: "f0",
96+
CookieFieldnames.CONTENTS: "{'c': 'f2222'}",
97+
}
98+
99+
result = await dataface.update_cookie(
100+
record,
101+
)
102+
103+
assert result["count"] == 1
104+
records = await dataface.query(all_sql)
105+
106+
assert len(records) == 1
107+
assert records[0][CookieFieldnames.UUID] == "f0"
108+
assert records[0][CookieFieldnames.CONTENTS] == "{'c': 'f2222'}"

tests/test_dataface_takeover.py

Lines changed: 27 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,9 @@
11
import logging
22

33
from dls_servbase_api.databases.constants import CookieFieldnames, Tablenames
4-
5-
# Object managing datafaces.
4+
from dls_servbase_api.datafaces.context import Context as ClientContext
65
from dls_servbase_api.datafaces.datafaces import dls_servbase_datafaces_get_default
7-
8-
# Context creator.
9-
from dls_servbase_lib.contexts.contexts import Contexts
10-
from dls_servbase_lib.datafaces.context import Context as DatafaceContext
6+
from dls_servbase_lib.datafaces.context import Context as ServerContext
117

128
# Base class for the tester.
139
from tests.base_context_tester import BaseContextTester
@@ -36,37 +32,37 @@ async def _main_coroutine(self, constants, output_directory):
3632
dls_servbase_multiconf = self.get_multiconf()
3733

3834
context_configuration = await dls_servbase_multiconf.load()
39-
dls_servbase_context = Contexts().build_object(context_configuration)
40-
41-
async with dls_servbase_context:
42-
dataface = dls_servbase_datafaces_get_default()
43-
44-
# Write one record.
45-
await dataface.insert(
46-
Tablenames.COOKIES,
47-
[
48-
{
49-
CookieFieldnames.UUID: "f0",
50-
CookieFieldnames.CONTENTS: "{'a': 'f000'}",
51-
}
52-
],
53-
)
5435

55-
# Make a new dataface context with the same specification.
56-
dataface_specification = dls_servbase_multiconf.require(
57-
"dls_servbase_dataface_specification"
58-
)
36+
servbase_specification = context_configuration[
37+
"dls_servbase_dataface_specification"
38+
]
39+
40+
dls_servbase_client_context = ClientContext(servbase_specification)
41+
42+
dls_servbase_server_context = ServerContext(servbase_specification)
5943

44+
async with dls_servbase_client_context:
45+
async with dls_servbase_server_context:
46+
dataface = dls_servbase_datafaces_get_default()
47+
48+
# Write one record.
49+
await dataface.insert(
50+
Tablenames.COOKIES,
51+
[
52+
{
53+
CookieFieldnames.UUID: "f0",
54+
CookieFieldnames.CONTENTS: "{'a': 'f000'}",
55+
}
56+
],
57+
)
58+
59+
# Make a new dataface context with the same specification.
60+
dls_servbase_server_context = ServerContext(servbase_specification)
6061
# Activate the new dataface which should send shutdown to the old process.
61-
async with DatafaceContext(dataface_specification):
62+
async with dls_servbase_server_context:
6263
all_sql = f"SELECT * FROM {Tablenames.COOKIES}"
6364
records = await dataface.query(all_sql)
6465

6566
assert len(records) == 1
6667
assert records[0][CookieFieldnames.UUID] == "f0"
6768
assert records[0][CookieFieldnames.CONTENTS] == "{'a': 'f000'}"
68-
69-
# From the top level context's point of view, one of its processs is dead.
70-
assert await dls_servbase_context.is_any_process_dead()
71-
72-
assert not await dls_servbase_context.is_any_process_alive()

0 commit comments

Comments
 (0)