Skip to content

Commit af01a31

Browse files
committed
Add support for Managed Service
1 parent b40fb15 commit af01a31

5 files changed

Lines changed: 68 additions & 4 deletions

File tree

singlestoredb/apps/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
from ._cloud_functions import run_function_app # noqa: F401
22
from ._dashboards import run_dashboard_app # noqa: F401
3+
from ._python_udfs import run_udf_app # noqa: F401

singlestoredb/apps/_python_udfs.py

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import asyncio
2+
import textwrap
3+
import typing
4+
5+
from ._config import AppConfig
6+
from ._connection_info import ConnectionInfo
7+
from ._process import kill_process_by_port
8+
from ..functions.ext.asgi import Application
9+
10+
if typing.TYPE_CHECKING:
11+
from ._uvicorn_util import AwaitableUvicornServer
12+
13+
# Keep track of currently running server
14+
_running_server: 'typing.Optional[AwaitableUvicornServer]' = None
15+
16+
17+
async def run_udf_app(
18+
app: Application,
19+
log_level: str = 'error',
20+
kill_existing_app_server: bool = True,
21+
) -> ConnectionInfo:
22+
global _running_server
23+
from ._uvicorn_util import AwaitableUvicornServer
24+
25+
try:
26+
import uvicorn
27+
except ImportError:
28+
raise ImportError('package uvicorn is required to run python udfs')
29+
30+
app_config = AppConfig.from_env()
31+
32+
if kill_existing_app_server:
33+
# Shutdown the server gracefully if it was started by us.
34+
# Since the uvicorn server doesn't start a new subprocess
35+
# killing the process would result in kernel dying.
36+
if _running_server is not None:
37+
await _running_server.shutdown()
38+
_running_server = None
39+
40+
# Kill if any other process is occupying the port
41+
kill_process_by_port(app_config.listen_port)
42+
43+
app.root_path = app_config.base_path
44+
45+
config = uvicorn.Config(
46+
app,
47+
host='0.0.0.0',
48+
port=app_config.listen_port,
49+
log_level=log_level,
50+
)
51+
_running_server = AwaitableUvicornServer(config)
52+
53+
app.register_functions(replace=True)
54+
asyncio.create_task(_running_server.serve())
55+
await _running_server.wait_for_startup()
56+
57+
connection_info = ConnectionInfo(app_config.base_url, app_config.token)
58+
59+
print(
60+
'Following Python UDFs are available: ', app.get_function_info()
61+
)
62+
63+
return connection_info

singlestoredb/config.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -317,9 +317,9 @@
317317
'external_function.app_mode', 'string',
318318
functools.partial(
319319
check_str,
320-
valid_values=['remote', 'collocated'],
320+
valid_values=['managed', 'remote', 'collocated'],
321321
),
322-
'remote',
322+
'managed',
323323
'Specifies the mode of operation of the external function application.',
324324
environ=['SINGLESTOREDB_EXT_FUNC_APP_MODE'],
325325
)

singlestoredb/functions/ext/asgi.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1318,7 +1318,7 @@ def main(argv: Optional[List[str]] = None) -> None:
13181318
link_name=args.link_name or None,
13191319
link_config=json.loads(args.link_config) or None,
13201320
link_credentials=json.loads(args.link_credentials) or None,
1321-
app_mode='remote',
1321+
app_mode='managed',
13221322
name_prefix=args.name_prefix,
13231323
name_suffix=args.name_suffix,
13241324
)

singlestoredb/functions/signature.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -734,7 +734,7 @@ def signature_to_sql(
734734
signature: Dict[str, Any],
735735
url: Optional[str] = None,
736736
data_format: str = 'rowdat_1',
737-
app_mode: str = 'remote',
737+
app_mode: str = 'managed',
738738
link: Optional[str] = None,
739739
replace: bool = False,
740740
) -> str:

0 commit comments

Comments
 (0)