Refactor ServiceFactory and Dependencies (#1560)
* Update dependencies for OpenTelemetry * Update service dependency logic and add first version of telemetry service * Remove telemetry service and related code
This commit is contained in:
parent
f672a1163d
commit
e8630dac7f
17 changed files with 246 additions and 133 deletions
36
poetry.lock
generated
36
poetry.lock
generated
|
|
@ -5262,6 +5262,21 @@ files = [
|
|||
deprecated = ">=1.2.6"
|
||||
importlib-metadata = ">=6.0,<7.0"
|
||||
|
||||
[[package]]
|
||||
name = "opentelemetry-exporter-otlp"
|
||||
version = "1.23.0"
|
||||
description = "OpenTelemetry Collector Exporters"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "opentelemetry_exporter_otlp-1.23.0-py3-none-any.whl", hash = "sha256:92371fdc8d7803465a45801fe30cd8c522ef355a385b0a1d5346d32f77511ea2"},
|
||||
{file = "opentelemetry_exporter_otlp-1.23.0.tar.gz", hash = "sha256:4af8798f9bc3bddb92fcbb5b4aa9d0e955d962aa1d9bceaab08891c355a9f907"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
opentelemetry-exporter-otlp-proto-grpc = "1.23.0"
|
||||
opentelemetry-exporter-otlp-proto-http = "1.23.0"
|
||||
|
||||
[[package]]
|
||||
name = "opentelemetry-exporter-otlp-proto-common"
|
||||
version = "1.23.0"
|
||||
|
|
@ -5382,6 +5397,27 @@ opentelemetry-util-http = "0.44b0"
|
|||
instruments = ["fastapi (>=0.58,<1.0)"]
|
||||
test = ["httpx (>=0.22,<1.0)", "opentelemetry-instrumentation-fastapi[instruments]", "opentelemetry-test-utils (==0.44b0)", "requests (>=2.23,<3.0)"]
|
||||
|
||||
[[package]]
|
||||
name = "opentelemetry-instrumentation-httpx"
|
||||
version = "0.44b0"
|
||||
description = "OpenTelemetry HTTPX Instrumentation"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "opentelemetry_instrumentation_httpx-0.44b0-py3-none-any.whl", hash = "sha256:a4f1121b6212b018e719ef6a9a2f8317c329edd01a61452b7250f574f7d95a91"},
|
||||
{file = "opentelemetry_instrumentation_httpx-0.44b0.tar.gz", hash = "sha256:6cc81c4182f54dfb0d15774e3e48bb90d3ed44e9ad8bf5eef2a64a7197f945d8"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
opentelemetry-api = ">=1.12,<2.0"
|
||||
opentelemetry-instrumentation = "0.44b0"
|
||||
opentelemetry-semantic-conventions = "0.44b0"
|
||||
opentelemetry-util-http = "0.44b0"
|
||||
|
||||
[package.extras]
|
||||
instruments = ["httpx (>=0.18.0)"]
|
||||
test = ["opentelemetry-instrumentation-httpx[instruments]", "opentelemetry-sdk (>=1.12,<2.0)", "opentelemetry-test-utils (==0.44b0)"]
|
||||
|
||||
[[package]]
|
||||
name = "opentelemetry-proto"
|
||||
version = "1.23.0"
|
||||
|
|
|
|||
|
|
@ -105,6 +105,12 @@ python-socketio = "^5.11.0"
|
|||
llama-index = "^0.10.13"
|
||||
langchain-openai = "^0.0.5"
|
||||
unstructured = { extras = ["md"], version = "^0.12.4" }
|
||||
opentelemetry-api = "^1.23.0"
|
||||
opentelemetry-sdk = "^1.23.0"
|
||||
opentelemetry-exporter-otlp = "^1.23.0"
|
||||
opentelemetry-instrumentation-fastapi = "^0.44b0"
|
||||
opentelemetry-instrumentation-httpx = "^0.44b0"
|
||||
opentelemetry-instrumentation-asgi = "^0.44b0"
|
||||
dspy-ai = "^2.4.0"
|
||||
crewai = "^0.22.5"
|
||||
langchain-anthropic = "^0.1.4"
|
||||
|
|
|
|||
|
|
@ -20,7 +20,9 @@ from langflow.utils.logger import configure
|
|||
def get_lifespan(fix_migration=False, socketio_server=None):
|
||||
@asynccontextmanager
|
||||
async def lifespan(app: FastAPI):
|
||||
initialize_services(fix_migration=fix_migration, socketio_server=socketio_server)
|
||||
initialize_services(
|
||||
fix_migration=fix_migration, socketio_server=socketio_server
|
||||
)
|
||||
setup_llm_caching()
|
||||
LangfuseInstance.update()
|
||||
create_or_update_starter_projects()
|
||||
|
|
@ -34,7 +36,9 @@ def create_app():
|
|||
"""Create the FastAPI app and include the router."""
|
||||
|
||||
configure()
|
||||
socketio_server = socketio.AsyncServer(async_mode="asgi", cors_allowed_origins="*", logger=True)
|
||||
socketio_server = socketio.AsyncServer(
|
||||
async_mode="asgi", cors_allowed_origins="*", logger=True
|
||||
)
|
||||
lifespan = get_lifespan(socketio_server=socketio_server)
|
||||
app = FastAPI(lifespan=lifespan)
|
||||
origins = ["*"]
|
||||
|
|
@ -101,7 +105,9 @@ def get_static_files_dir():
|
|||
return frontend_path / "frontend"
|
||||
|
||||
|
||||
def setup_app(static_files_dir: Optional[Path] = None, backend_only: bool = False) -> FastAPI:
|
||||
def setup_app(
|
||||
static_files_dir: Optional[Path] = None, backend_only: bool = False
|
||||
) -> FastAPI:
|
||||
"""Setup the FastAPI app."""
|
||||
# get the directory of the current file
|
||||
if not static_files_dir:
|
||||
|
|
|
|||
2
src/backend/langflow/services/cache/base.py
vendored
2
src/backend/langflow/services/cache/base.py
vendored
|
|
@ -6,7 +6,7 @@ from typing import Optional
|
|||
from langflow.services.base import Service
|
||||
|
||||
|
||||
class BaseCacheService(Service):
|
||||
class CacheService(Service):
|
||||
"""
|
||||
Abstract base class for a cache.
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ if TYPE_CHECKING:
|
|||
|
||||
class CacheServiceFactory(ServiceFactory):
|
||||
def __init__(self):
|
||||
super().__init__(BaseCacheService)
|
||||
super().__init__(CacheService)
|
||||
|
||||
def create(self, settings_service: "SettingsService"):
|
||||
# Here you would have logic to create and configure a CacheService
|
||||
|
|
|
|||
27
src/backend/langflow/services/cache/service.py
vendored
27
src/backend/langflow/services/cache/service.py
vendored
|
|
@ -68,7 +68,10 @@ class ThreadingInMemoryCache(BaseCacheService, Service):
|
|||
Retrieve an item from the cache without acquiring the lock.
|
||||
"""
|
||||
if item := self._cache.get(key):
|
||||
if self.expiration_time is None or time.time() - item["time"] < self.expiration_time:
|
||||
if (
|
||||
self.expiration_time is None
|
||||
or time.time() - item["time"] < self.expiration_time
|
||||
):
|
||||
# Move the key to the end to make it recently used
|
||||
self._cache.move_to_end(key)
|
||||
# Check if the value is pickled
|
||||
|
|
@ -113,7 +116,11 @@ class ThreadingInMemoryCache(BaseCacheService, Service):
|
|||
"""
|
||||
with lock or self._lock:
|
||||
existing_value = self._get_without_lock(key)
|
||||
if existing_value is not None and isinstance(existing_value, dict) and isinstance(value, dict):
|
||||
if (
|
||||
existing_value is not None
|
||||
and isinstance(existing_value, dict)
|
||||
and isinstance(value, dict)
|
||||
):
|
||||
existing_value.update(value)
|
||||
value = existing_value
|
||||
|
||||
|
|
@ -179,7 +186,7 @@ class ThreadingInMemoryCache(BaseCacheService, Service):
|
|||
return f"InMemoryCache(max_size={self.max_size}, expiration_time={self.expiration_time})"
|
||||
|
||||
|
||||
class RedisCache(BaseCacheService, Service):
|
||||
class RedisCache(CacheService):
|
||||
"""
|
||||
A Redis-based cache implementation.
|
||||
|
||||
|
|
@ -202,7 +209,9 @@ class RedisCache(BaseCacheService, Service):
|
|||
b = cache["b"]
|
||||
"""
|
||||
|
||||
def __init__(self, host="localhost", port=6379, db=0, url=None, expiration_time=60 * 60):
|
||||
def __init__(
|
||||
self, host="localhost", port=6379, db=0, url=None, expiration_time=60 * 60
|
||||
):
|
||||
"""
|
||||
Initialize a new RedisCache instance.
|
||||
|
||||
|
|
@ -270,7 +279,9 @@ class RedisCache(BaseCacheService, Service):
|
|||
if not result:
|
||||
raise ValueError("RedisCache could not set the value.")
|
||||
except TypeError as exc:
|
||||
raise TypeError("RedisCache only accepts values that can be pickled. ") from exc
|
||||
raise TypeError(
|
||||
"RedisCache only accepts values that can be pickled. "
|
||||
) from exc
|
||||
|
||||
def upsert(self, key, value):
|
||||
"""
|
||||
|
|
@ -282,7 +293,11 @@ class RedisCache(BaseCacheService, Service):
|
|||
value: The value to insert or update.
|
||||
"""
|
||||
existing_value = self.get(key)
|
||||
if existing_value is not None and isinstance(existing_value, dict) and isinstance(value, dict):
|
||||
if (
|
||||
existing_value is not None
|
||||
and isinstance(existing_value, dict)
|
||||
and isinstance(value, dict)
|
||||
):
|
||||
existing_value.update(value)
|
||||
value = existing_value
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,9 @@ from typing import TYPE_CHECKING, Generator
|
|||
from langflow.services import ServiceType, service_manager
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from langflow.services.cache.service import BaseCacheService
|
||||
from sqlmodel import Session
|
||||
|
||||
from langflow.services.cache.service import CacheService
|
||||
from langflow.services.chat.service import ChatService
|
||||
from langflow.services.credentials.service import CredentialService
|
||||
from langflow.services.database.service import DatabaseService
|
||||
|
|
@ -16,11 +18,10 @@ if TYPE_CHECKING:
|
|||
from langflow.services.storage.service import StorageService
|
||||
from langflow.services.store.service import StoreService
|
||||
from langflow.services.task.service import TaskService
|
||||
from sqlmodel import Session
|
||||
|
||||
|
||||
def get_socket_service() -> "SocketIOService":
|
||||
return service_manager.get(ServiceType.SOCKET_IO_SERVICE) # type: ignore
|
||||
return service_manager.get(ServiceType.SOCKETIO_SERVICE) # type: ignore
|
||||
|
||||
|
||||
def get_storage_service() -> "StorageService":
|
||||
|
|
|
|||
|
|
@ -1,12 +1,91 @@
|
|||
from typing import TYPE_CHECKING
|
||||
import importlib
|
||||
import inspect
|
||||
from typing import TYPE_CHECKING, Type, get_type_hints
|
||||
|
||||
from cachetools import LRUCache, cached
|
||||
from loguru import logger
|
||||
|
||||
from langflow.services.schema import ServiceType
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from langflow.services.base import Service
|
||||
|
||||
|
||||
class ServiceFactory:
|
||||
def __init__(self, service_class):
|
||||
def __init__(
|
||||
self,
|
||||
service_class,
|
||||
):
|
||||
self.service_class = service_class
|
||||
self.dependencies = infer_service_types(self, import_all_services_into_a_dict())
|
||||
|
||||
def create(self, *args, **kwargs) -> "Service":
|
||||
raise NotImplementedError
|
||||
raise self.service_class(*args, **kwargs)
|
||||
|
||||
|
||||
def hash_factory(factory: ServiceFactory) -> str:
|
||||
return factory.service_class.__name__
|
||||
|
||||
|
||||
def hash_dict(d: dict) -> str:
|
||||
return str(d)
|
||||
|
||||
|
||||
def hash_infer_service_types_args(
|
||||
factory_class: Type[ServiceFactory], available_services=None
|
||||
) -> str:
|
||||
factory_hash = hash_factory(factory_class)
|
||||
services_hash = hash_dict(available_services)
|
||||
return f"{factory_hash}_{services_hash}"
|
||||
|
||||
|
||||
@cached(cache=LRUCache(maxsize=10), key=hash_infer_service_types_args)
|
||||
def infer_service_types(
|
||||
factory_class: Type[ServiceFactory], available_services=None
|
||||
) -> "ServiceType":
|
||||
create_method = factory_class.create
|
||||
type_hints = get_type_hints(create_method, globalns=available_services)
|
||||
service_types = []
|
||||
for param_name, param_type in type_hints.items():
|
||||
# Skip the return type if it's included in type hints
|
||||
if param_name == "return":
|
||||
continue
|
||||
|
||||
# Convert the type to the expected enum format directly without appending "_SERVICE"
|
||||
type_name = param_type.__name__.upper().replace("SERVICE", "_SERVICE")
|
||||
|
||||
try:
|
||||
# Attempt to find a matching enum value
|
||||
service_type = ServiceType[type_name]
|
||||
service_types.append(service_type)
|
||||
except KeyError:
|
||||
raise ValueError(
|
||||
f"No matching ServiceType for parameter type: {param_type.__name__}"
|
||||
)
|
||||
return service_types
|
||||
|
||||
|
||||
@cached(cache=LRUCache(maxsize=1))
|
||||
def import_all_services_into_a_dict():
|
||||
# Services are all in langflow.services.{service_name}.service
|
||||
# and are subclass of Service
|
||||
# We want to import all of them and put them in a dict
|
||||
# to use as globals
|
||||
from langflow.services.base import Service
|
||||
|
||||
services = {}
|
||||
for service_type in ServiceType:
|
||||
try:
|
||||
service_name = ServiceType(service_type).value.replace("_service", "")
|
||||
module_name = f"langflow.services.{service_name}.service"
|
||||
module = importlib.import_module(module_name)
|
||||
for name, obj in inspect.getmembers(module, inspect.isclass):
|
||||
if issubclass(obj, Service) and obj is not Service:
|
||||
services[name] = obj
|
||||
break
|
||||
except Exception as exc:
|
||||
logger.exception(exc)
|
||||
raise RuntimeError(
|
||||
f"Could not initialize services. Please check your settings."
|
||||
) from exc
|
||||
return services
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
from typing import TYPE_CHECKING, Dict, List, Optional
|
||||
from typing import TYPE_CHECKING, Dict
|
||||
|
||||
from langflow.services.schema import ServiceType
|
||||
from loguru import logger
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from langflow.services.base import Service
|
||||
from langflow.services.factory import ServiceFactory
|
||||
from langflow.services.schema import ServiceType
|
||||
|
||||
|
||||
class ServiceManager:
|
||||
|
|
@ -16,23 +16,19 @@ class ServiceManager:
|
|||
def __init__(self):
|
||||
self.services: Dict[str, "Service"] = {}
|
||||
self.factories = {}
|
||||
self.dependencies = {}
|
||||
|
||||
def register_factory(
|
||||
self,
|
||||
service_factory: "ServiceFactory",
|
||||
dependencies: Optional[List[ServiceType]] = None,
|
||||
):
|
||||
"""
|
||||
Registers a new factory with dependencies.
|
||||
"""
|
||||
if dependencies is None:
|
||||
dependencies = []
|
||||
|
||||
service_name = service_factory.service_class.name
|
||||
self.factories[service_name] = service_factory
|
||||
self.dependencies[service_name] = dependencies
|
||||
|
||||
def get(self, service_name: ServiceType) -> "Service":
|
||||
def get(self, service_name: "ServiceType") -> "Service":
|
||||
"""
|
||||
Get (or create) a service by its name.
|
||||
"""
|
||||
|
|
@ -41,7 +37,7 @@ class ServiceManager:
|
|||
|
||||
return self.services[service_name]
|
||||
|
||||
def _create_service(self, service_name: ServiceType):
|
||||
def _create_service(self, service_name: "ServiceType"):
|
||||
"""
|
||||
Create a new service given its name, handling dependencies.
|
||||
"""
|
||||
|
|
@ -49,25 +45,32 @@ class ServiceManager:
|
|||
self._validate_service_creation(service_name)
|
||||
|
||||
# Create dependencies first
|
||||
for dependency in self.dependencies.get(service_name, []):
|
||||
factory = self.factories.get(service_name)
|
||||
for dependency in factory.dependencies:
|
||||
if dependency not in self.services:
|
||||
self._create_service(dependency)
|
||||
|
||||
# Collect the dependent services
|
||||
dependent_services = {dep.value: self.services[dep] for dep in self.dependencies.get(service_name, [])}
|
||||
dependent_services = {
|
||||
dep.value: self.services[dep] for dep in factory.dependencies
|
||||
}
|
||||
|
||||
# Create the actual service
|
||||
self.services[service_name] = self.factories[service_name].create(**dependent_services)
|
||||
self.services[service_name] = self.factories[service_name].create(
|
||||
**dependent_services
|
||||
)
|
||||
self.services[service_name].set_ready()
|
||||
|
||||
def _validate_service_creation(self, service_name: ServiceType):
|
||||
def _validate_service_creation(self, service_name: "ServiceType"):
|
||||
"""
|
||||
Validate whether the service can be created.
|
||||
"""
|
||||
if service_name not in self.factories:
|
||||
raise ValueError(f"No factory registered for the service class '{service_name.name}'")
|
||||
raise ValueError(
|
||||
f"No factory registered for the service class '{service_name.name}'"
|
||||
)
|
||||
|
||||
def update(self, service_name: ServiceType):
|
||||
def update(self, service_name: "ServiceType"):
|
||||
"""
|
||||
Update a service by its name.
|
||||
"""
|
||||
|
|
@ -90,36 +93,11 @@ class ServiceManager:
|
|||
logger.exception(exc)
|
||||
self.services = {}
|
||||
self.factories = {}
|
||||
self.dependencies = {}
|
||||
|
||||
|
||||
service_manager = ServiceManager()
|
||||
|
||||
|
||||
def reinitialize_services():
|
||||
"""
|
||||
Reinitialize all the services needed.
|
||||
"""
|
||||
|
||||
service_manager.update(ServiceType.SETTINGS_SERVICE)
|
||||
service_manager.update(ServiceType.DATABASE_SERVICE)
|
||||
service_manager.update(ServiceType.CACHE_SERVICE)
|
||||
service_manager.update(ServiceType.CHAT_SERVICE)
|
||||
service_manager.update(ServiceType.SESSION_SERVICE)
|
||||
service_manager.update(ServiceType.AUTH_SERVICE)
|
||||
service_manager.update(ServiceType.TASK_SERVICE)
|
||||
|
||||
# Test cache connection
|
||||
service_manager.get(ServiceType.CACHE_SERVICE)
|
||||
# Test database connection
|
||||
service_manager.get(ServiceType.DATABASE_SERVICE)
|
||||
|
||||
# Test cache connection
|
||||
service_manager.get(ServiceType.CACHE_SERVICE)
|
||||
# Test database connection
|
||||
service_manager.get(ServiceType.DATABASE_SERVICE)
|
||||
|
||||
|
||||
def initialize_settings_service():
|
||||
"""
|
||||
Initialize the settings manager.
|
||||
|
|
@ -134,13 +112,12 @@ def initialize_session_service():
|
|||
Initialize the session manager.
|
||||
"""
|
||||
from langflow.services.cache import factory as cache_factory
|
||||
from langflow.services.session import factory as session_service_factory # type: ignore
|
||||
from langflow.services.session import (
|
||||
factory as session_service_factory,
|
||||
) # type: ignore
|
||||
|
||||
initialize_settings_service()
|
||||
|
||||
service_manager.register_factory(cache_factory.CacheServiceFactory(), dependencies=[ServiceType.SETTINGS_SERVICE])
|
||||
service_manager.register_factory(cache_factory.CacheServiceFactory())
|
||||
|
||||
service_manager.register_factory(
|
||||
session_service_factory.SessionServiceFactory(),
|
||||
dependencies=[ServiceType.CACHE_SERVICE],
|
||||
)
|
||||
service_manager.register_factory(session_service_factory.SessionServiceFactory())
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
from langflow.services.factory import ServiceFactory
|
||||
from langflow.services.monitor.service import MonitorService
|
||||
from langflow.services.schema import ServiceType
|
||||
|
||||
|
||||
class MonitorServiceFactory(ServiceFactory):
|
||||
|
|
|
|||
|
|
@ -14,9 +14,9 @@ class ServiceType(str, Enum):
|
|||
CHAT_SERVICE = "chat_service"
|
||||
SESSION_SERVICE = "session_service"
|
||||
TASK_SERVICE = "task_service"
|
||||
PLUGIN_SERVICE = "plugin_service"
|
||||
PLUGINS_SERVICE = "plugins_service"
|
||||
STORE_SERVICE = "store_service"
|
||||
CREDENTIAL_SERVICE = "credential_service"
|
||||
CREDENTIALS_SERVICE = "credentials_service"
|
||||
STORAGE_SERVICE = "storage_service"
|
||||
MONITOR_SERVICE = "monitor_service"
|
||||
SOCKET_IO_SERVICE = "socket_io_service"
|
||||
SOCKETIO_SERVICE = "socket_service"
|
||||
|
|
|
|||
|
|
@ -1,14 +1,15 @@
|
|||
from typing import TYPE_CHECKING
|
||||
from langflow.services.session.service import SessionService
|
||||
|
||||
from langflow.services.factory import ServiceFactory
|
||||
from langflow.services.session.service import SessionService
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from langflow.services.cache.service import BaseCacheService
|
||||
from langflow.services.cache.service import CacheService
|
||||
|
||||
|
||||
class SessionServiceFactory(ServiceFactory):
|
||||
def __init__(self):
|
||||
super().__init__(SessionService)
|
||||
|
||||
def create(self, cache_service: "BaseCacheService"):
|
||||
def create(self, cache_service: "CacheService"):
|
||||
return SessionService(cache_service)
|
||||
|
|
|
|||
|
|
@ -5,14 +5,14 @@ from langflow.services.base import Service
|
|||
from langflow.services.session.utils import compute_dict_hash, session_id_generator
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from langflow.services.cache.base import BaseCacheService
|
||||
from langflow.services.cache.base import CacheService
|
||||
|
||||
|
||||
class SessionService(Service):
|
||||
name = "session_service"
|
||||
|
||||
def __init__(self, cache_service):
|
||||
self.cache_service: "BaseCacheService" = cache_service
|
||||
self.cache_service: "CacheService" = cache_service
|
||||
|
||||
async def load_session(self, key, flow_id: str, data_graph: Optional[dict] = None):
|
||||
# Check if the data is cached
|
||||
|
|
|
|||
|
|
@ -1,15 +1,18 @@
|
|||
from typing import TYPE_CHECKING
|
||||
|
||||
from langflow.services.factory import ServiceFactory
|
||||
from langflow.services.schema import ServiceType
|
||||
from langflow.services.socket.service import SocketIOService
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from langflow.services.cache.service import BaseCacheService
|
||||
from langflow.services.cache.service import CacheService
|
||||
|
||||
|
||||
class SocketIOFactory(ServiceFactory):
|
||||
def __init__(self):
|
||||
super().__init__(service_class=SocketIOService)
|
||||
super().__init__(
|
||||
service_class=SocketIOService,
|
||||
)
|
||||
|
||||
def create(self, cache_service: "BaseCacheService"):
|
||||
def create(self, cache_service: "CacheService"):
|
||||
return SocketIOService(cache_service)
|
||||
|
|
|
|||
|
|
@ -8,13 +8,13 @@ from langflow.services.deps import get_chat_service
|
|||
from langflow.services.socket.utils import build_vertex, get_vertices
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from langflow.services.cache.service import BaseCacheService
|
||||
from langflow.services.cache.service import CacheService
|
||||
|
||||
|
||||
class SocketIOService(Service):
|
||||
name = "socket_io_service"
|
||||
name = "socket_service"
|
||||
|
||||
def __init__(self, cache_service: "BaseCacheService"):
|
||||
def __init__(self, cache_service: "CacheService"):
|
||||
self.cache_service = cache_service
|
||||
|
||||
def init(self, sio: socketio.AsyncServer):
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
from typing import TYPE_CHECKING
|
||||
|
||||
from langflow.services.factory import ServiceFactory
|
||||
from langflow.services.schema import ServiceType
|
||||
from langflow.services.storage.service import StorageService
|
||||
from loguru import logger
|
||||
|
||||
|
|
@ -11,9 +12,13 @@ if TYPE_CHECKING:
|
|||
|
||||
class StorageServiceFactory(ServiceFactory):
|
||||
def __init__(self):
|
||||
super().__init__(StorageService)
|
||||
super().__init__(
|
||||
StorageService,
|
||||
)
|
||||
|
||||
def create(self, session_service: "SessionService", settings_service: "SettingsService"):
|
||||
def create(
|
||||
self, session_service: "SessionService", settings_service: "SettingsService"
|
||||
):
|
||||
storage_type = settings_service.settings.STORAGE_TYPE
|
||||
if storage_type.lower() == "local":
|
||||
from .local import LocalStorageService
|
||||
|
|
@ -24,7 +29,9 @@ class StorageServiceFactory(ServiceFactory):
|
|||
|
||||
return S3StorageService(session_service, settings_service)
|
||||
else:
|
||||
logger.warning(f"Storage type {storage_type} not supported. Using local storage.")
|
||||
logger.warning(
|
||||
f"Storage type {storage_type} not supported. Using local storage."
|
||||
)
|
||||
from .local import LocalStorageService
|
||||
|
||||
return LocalStorageService(session_service, settings_service)
|
||||
|
|
|
|||
|
|
@ -1,8 +1,12 @@
|
|||
import importlib
|
||||
import inspect
|
||||
|
||||
from loguru import logger
|
||||
from sqlmodel import Session, select
|
||||
|
||||
from langflow.services.auth.utils import create_super_user, verify_password
|
||||
from langflow.services.database.utils import initialize_database
|
||||
from langflow.services.factory import ServiceFactory
|
||||
from langflow.services.manager import service_manager
|
||||
from langflow.services.schema import ServiceType
|
||||
from langflow.services.settings.constants import (
|
||||
|
|
@ -14,56 +18,32 @@ from langflow.services.socket.utils import set_socketio_server
|
|||
from .deps import get_db_service, get_session, get_settings_service
|
||||
|
||||
|
||||
def get_factories_and_deps():
|
||||
from langflow.services.auth import factory as auth_factory
|
||||
from langflow.services.cache import factory as cache_factory
|
||||
from langflow.services.chat import factory as chat_factory
|
||||
from langflow.services.credentials import factory as credentials_factory
|
||||
from langflow.services.database import factory as database_factory
|
||||
from langflow.services.monitor import factory as monitor_factory
|
||||
from langflow.services.plugins import factory as plugins_factory
|
||||
from langflow.services.session import (
|
||||
factory as session_service_factory,
|
||||
) # type: ignore
|
||||
from langflow.services.settings import factory as settings_factory
|
||||
from langflow.services.socket import factory as socket_factory
|
||||
from langflow.services.storage import factory as storage_factory
|
||||
from langflow.services.store import factory as store_factory
|
||||
from langflow.services.task import factory as task_factory
|
||||
|
||||
return [
|
||||
(settings_factory.SettingsServiceFactory(), []),
|
||||
(
|
||||
auth_factory.AuthServiceFactory(),
|
||||
[ServiceType.SETTINGS_SERVICE],
|
||||
),
|
||||
(
|
||||
database_factory.DatabaseServiceFactory(),
|
||||
[ServiceType.SETTINGS_SERVICE],
|
||||
),
|
||||
(
|
||||
cache_factory.CacheServiceFactory(),
|
||||
[ServiceType.SETTINGS_SERVICE],
|
||||
),
|
||||
(chat_factory.ChatServiceFactory(), []),
|
||||
(task_factory.TaskServiceFactory(), []),
|
||||
(
|
||||
session_service_factory.SessionServiceFactory(),
|
||||
[ServiceType.CACHE_SERVICE],
|
||||
),
|
||||
(plugins_factory.PluginServiceFactory(), [ServiceType.SETTINGS_SERVICE]),
|
||||
(store_factory.StoreServiceFactory(), [ServiceType.SETTINGS_SERVICE]),
|
||||
(
|
||||
credentials_factory.CredentialServiceFactory(),
|
||||
[ServiceType.SETTINGS_SERVICE],
|
||||
),
|
||||
(
|
||||
storage_factory.StorageServiceFactory(),
|
||||
[ServiceType.SESSION_SERVICE, ServiceType.SETTINGS_SERVICE],
|
||||
),
|
||||
(monitor_factory.MonitorServiceFactory(), [ServiceType.SETTINGS_SERVICE]),
|
||||
(socket_factory.SocketIOFactory(), [ServiceType.CACHE_SERVICE]),
|
||||
def get_factories():
|
||||
service_names = [
|
||||
ServiceType(service_type).value.replace("_service", "")
|
||||
for service_type in ServiceType
|
||||
]
|
||||
base_module = "langflow.services"
|
||||
factories = []
|
||||
|
||||
for name in service_names:
|
||||
try:
|
||||
module_name = f"{base_module}.{name}.factory"
|
||||
module = importlib.import_module(module_name)
|
||||
|
||||
# Find all classes in the module that are subclasses of ServiceFactory
|
||||
for name, obj in inspect.getmembers(module, inspect.isclass):
|
||||
if issubclass(obj, ServiceFactory) and obj is not ServiceFactory:
|
||||
factories.append(obj())
|
||||
break
|
||||
|
||||
except Exception as exc:
|
||||
logger.exception(exc)
|
||||
raise RuntimeError(
|
||||
f"Could not initialize services. Please check your settings."
|
||||
) from exc
|
||||
|
||||
return factories
|
||||
|
||||
|
||||
def get_or_create_super_user(session: Session, username, password, is_default):
|
||||
|
|
@ -198,11 +178,12 @@ def initialize_session_service():
|
|||
|
||||
initialize_settings_service()
|
||||
|
||||
service_manager.register_factory(cache_factory.CacheServiceFactory(), dependencies=[ServiceType.SETTINGS_SERVICE])
|
||||
service_manager.register_factory(
|
||||
cache_factory.CacheServiceFactory(),
|
||||
)
|
||||
|
||||
service_manager.register_factory(
|
||||
session_service_factory.SessionServiceFactory(),
|
||||
dependencies=[ServiceType.CACHE_SERVICE],
|
||||
)
|
||||
|
||||
|
||||
|
|
@ -210,9 +191,9 @@ def initialize_services(fix_migration: bool = False, socketio_server=None):
|
|||
"""
|
||||
Initialize all the services needed.
|
||||
"""
|
||||
for factory, dependencies in get_factories_and_deps():
|
||||
for factory in get_factories():
|
||||
try:
|
||||
service_manager.register_factory(factory, dependencies=dependencies)
|
||||
service_manager.register_factory(factory)
|
||||
except Exception as exc:
|
||||
logger.exception(exc)
|
||||
raise RuntimeError("Could not initialize services. Please check your settings.") from exc
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue