Skip to content

Commit 584e9b1

Browse files
authored
fix: Run feature server w/o gunicorn on windows (#4024)
* fix: Run feature server w/o gunicorn on windows Signed-off-by: tokoko <togurg14@freeuni.edu.ge> * skip gunicorn for windows in setup.py Signed-off-by: tokoko <togurg14@freeuni.edu.ge> * pull default registry ttl to constants Signed-off-by: tokoko <togurg14@freeuni.edu.ge> * remove default value from start_server as well Signed-off-by: tokoko <togurg14@freeuni.edu.ge> --------- Signed-off-by: tokoko <togurg14@freeuni.edu.ge>
1 parent f09c612 commit 584e9b1

File tree

3 files changed

+43
-27
lines changed

3 files changed

+43
-27
lines changed

sdk/python/feast/constants.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,3 +49,6 @@
4949

5050
# Environment variable for feature server docker image tag
5151
DOCKER_IMAGE_TAG_ENV_NAME: str = "FEAST_SERVER_DOCKER_IMAGE_TAG"
52+
53+
# Default feature server registry ttl (seconds)
54+
DEFAULT_FEATURE_SERVER_REGISTRY_TTL = 5

sdk/python/feast/feature_server.py

Lines changed: 39 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import json
2+
import sys
23
import threading
34
import traceback
45
import warnings
56
from typing import List, Optional
67

7-
import gunicorn.app.base
88
import pandas as pd
99
from dateutil import parser
1010
from fastapi import FastAPI, HTTPException, Request, Response, status
@@ -15,6 +15,7 @@
1515

1616
import feast
1717
from feast import proto_json, utils
18+
from feast.constants import DEFAULT_FEATURE_SERVER_REGISTRY_TTL
1819
from feast.data_source import PushMode
1920
from feast.errors import PushSourceNotFoundException
2021
from feast.protos.feast.serving.ServingService_pb2 import GetOnlineFeaturesRequest
@@ -45,7 +46,10 @@ class MaterializeIncrementalRequest(BaseModel):
4546
feature_views: Optional[List[str]] = None
4647

4748

48-
def get_app(store: "feast.FeatureStore", registry_ttl_sec: int = 5):
49+
def get_app(
50+
store: "feast.FeatureStore",
51+
registry_ttl_sec: int = DEFAULT_FEATURE_SERVER_REGISTRY_TTL,
52+
):
4953
proto_json.patch()
5054

5155
app = FastAPI()
@@ -202,24 +206,27 @@ def materialize_incremental(body=Depends(get_body)):
202206
return app
203207

204208

205-
class FeastServeApplication(gunicorn.app.base.BaseApplication):
206-
def __init__(self, store: "feast.FeatureStore", **options):
207-
self._app = get_app(
208-
store=store,
209-
registry_ttl_sec=options.get("registry_ttl_sec", 5),
210-
)
211-
self._options = options
212-
super().__init__()
209+
if sys.platform != "win32":
210+
import gunicorn.app.base
213211

214-
def load_config(self):
215-
for key, value in self._options.items():
216-
if key.lower() in self.cfg.settings and value is not None:
217-
self.cfg.set(key.lower(), value)
212+
class FeastServeApplication(gunicorn.app.base.BaseApplication):
213+
def __init__(self, store: "feast.FeatureStore", **options):
214+
self._app = get_app(
215+
store=store,
216+
registry_ttl_sec=options["registry_ttl_sec"],
217+
)
218+
self._options = options
219+
super().__init__()
220+
221+
def load_config(self):
222+
for key, value in self._options.items():
223+
if key.lower() in self.cfg.settings and value is not None:
224+
self.cfg.set(key.lower(), value)
218225

219-
self.cfg.set("worker_class", "uvicorn.workers.UvicornWorker")
226+
self.cfg.set("worker_class", "uvicorn.workers.UvicornWorker")
220227

221-
def load(self):
222-
return self._app
228+
def load(self):
229+
return self._app
223230

224231

225232
def start_server(
@@ -229,13 +236,19 @@ def start_server(
229236
no_access_log: bool,
230237
workers: int,
231238
keep_alive_timeout: int,
232-
registry_ttl_sec: int = 5,
239+
registry_ttl_sec: int,
233240
):
234-
FeastServeApplication(
235-
store=store,
236-
bind=f"{host}:{port}",
237-
accesslog=None if no_access_log else "-",
238-
workers=workers,
239-
keepalive=keep_alive_timeout,
240-
registry_ttl_sec=registry_ttl_sec,
241-
).run()
241+
if sys.platform != "win32":
242+
FeastServeApplication(
243+
store=store,
244+
bind=f"{host}:{port}",
245+
accesslog=None if no_access_log else "-",
246+
workers=workers,
247+
keepalive=keep_alive_timeout,
248+
registry_ttl_sec=registry_ttl_sec,
249+
).run()
250+
else:
251+
import uvicorn
252+
253+
app = get_app(store, registry_ttl_sec)
254+
uvicorn.run(app, host=host, port=port, access_log=(not no_access_log))

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@
6565
"typeguard>=4.0.0",
6666
"fastapi>=0.68.0",
6767
"uvicorn[standard]>=0.14.0,<1",
68-
"gunicorn",
68+
"gunicorn; platform_system != 'Windows'",
6969
# https://github.com/dask/dask/issues/10996
7070
"dask>=2021.1.0,<2024.3.0",
7171
"bowler", # Needed for automatic repo upgrades

0 commit comments

Comments
 (0)