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"
|
deprecated = ">=1.2.6"
|
||||||
importlib-metadata = ">=6.0,<7.0"
|
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]]
|
[[package]]
|
||||||
name = "opentelemetry-exporter-otlp-proto-common"
|
name = "opentelemetry-exporter-otlp-proto-common"
|
||||||
version = "1.23.0"
|
version = "1.23.0"
|
||||||
|
|
@ -5382,6 +5397,27 @@ opentelemetry-util-http = "0.44b0"
|
||||||
instruments = ["fastapi (>=0.58,<1.0)"]
|
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)"]
|
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]]
|
[[package]]
|
||||||
name = "opentelemetry-proto"
|
name = "opentelemetry-proto"
|
||||||
version = "1.23.0"
|
version = "1.23.0"
|
||||||
|
|
|
||||||
|
|
@ -105,6 +105,12 @@ python-socketio = "^5.11.0"
|
||||||
llama-index = "^0.10.13"
|
llama-index = "^0.10.13"
|
||||||
langchain-openai = "^0.0.5"
|
langchain-openai = "^0.0.5"
|
||||||
unstructured = { extras = ["md"], version = "^0.12.4" }
|
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"
|
dspy-ai = "^2.4.0"
|
||||||
crewai = "^0.22.5"
|
crewai = "^0.22.5"
|
||||||
langchain-anthropic = "^0.1.4"
|
langchain-anthropic = "^0.1.4"
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,9 @@ from langflow.utils.logger import configure
|
||||||
def get_lifespan(fix_migration=False, socketio_server=None):
|
def get_lifespan(fix_migration=False, socketio_server=None):
|
||||||
@asynccontextmanager
|
@asynccontextmanager
|
||||||
async def lifespan(app: FastAPI):
|
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()
|
setup_llm_caching()
|
||||||
LangfuseInstance.update()
|
LangfuseInstance.update()
|
||||||
create_or_update_starter_projects()
|
create_or_update_starter_projects()
|
||||||
|
|
@ -34,7 +36,9 @@ def create_app():
|
||||||
"""Create the FastAPI app and include the router."""
|
"""Create the FastAPI app and include the router."""
|
||||||
|
|
||||||
configure()
|
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)
|
lifespan = get_lifespan(socketio_server=socketio_server)
|
||||||
app = FastAPI(lifespan=lifespan)
|
app = FastAPI(lifespan=lifespan)
|
||||||
origins = ["*"]
|
origins = ["*"]
|
||||||
|
|
@ -101,7 +105,9 @@ def get_static_files_dir():
|
||||||
return frontend_path / "frontend"
|
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."""
|
"""Setup the FastAPI app."""
|
||||||
# get the directory of the current file
|
# get the directory of the current file
|
||||||
if not static_files_dir:
|
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
|
from langflow.services.base import Service
|
||||||
|
|
||||||
|
|
||||||
class BaseCacheService(Service):
|
class CacheService(Service):
|
||||||
"""
|
"""
|
||||||
Abstract base class for a cache.
|
Abstract base class for a cache.
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ if TYPE_CHECKING:
|
||||||
|
|
||||||
class CacheServiceFactory(ServiceFactory):
|
class CacheServiceFactory(ServiceFactory):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super().__init__(BaseCacheService)
|
super().__init__(CacheService)
|
||||||
|
|
||||||
def create(self, settings_service: "SettingsService"):
|
def create(self, settings_service: "SettingsService"):
|
||||||
# Here you would have logic to create and configure a CacheService
|
# 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.
|
Retrieve an item from the cache without acquiring the lock.
|
||||||
"""
|
"""
|
||||||
if item := self._cache.get(key):
|
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
|
# Move the key to the end to make it recently used
|
||||||
self._cache.move_to_end(key)
|
self._cache.move_to_end(key)
|
||||||
# Check if the value is pickled
|
# Check if the value is pickled
|
||||||
|
|
@ -113,7 +116,11 @@ class ThreadingInMemoryCache(BaseCacheService, Service):
|
||||||
"""
|
"""
|
||||||
with lock or self._lock:
|
with lock or self._lock:
|
||||||
existing_value = self._get_without_lock(key)
|
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)
|
existing_value.update(value)
|
||||||
value = existing_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})"
|
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.
|
A Redis-based cache implementation.
|
||||||
|
|
||||||
|
|
@ -202,7 +209,9 @@ class RedisCache(BaseCacheService, Service):
|
||||||
b = cache["b"]
|
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.
|
Initialize a new RedisCache instance.
|
||||||
|
|
||||||
|
|
@ -270,7 +279,9 @@ class RedisCache(BaseCacheService, Service):
|
||||||
if not result:
|
if not result:
|
||||||
raise ValueError("RedisCache could not set the value.")
|
raise ValueError("RedisCache could not set the value.")
|
||||||
except TypeError as exc:
|
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):
|
def upsert(self, key, value):
|
||||||
"""
|
"""
|
||||||
|
|
@ -282,7 +293,11 @@ class RedisCache(BaseCacheService, Service):
|
||||||
value: The value to insert or update.
|
value: The value to insert or update.
|
||||||
"""
|
"""
|
||||||
existing_value = self.get(key)
|
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)
|
existing_value.update(value)
|
||||||
value = existing_value
|
value = existing_value
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,9 @@ from typing import TYPE_CHECKING, Generator
|
||||||
from langflow.services import ServiceType, service_manager
|
from langflow.services import ServiceType, service_manager
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
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.chat.service import ChatService
|
||||||
from langflow.services.credentials.service import CredentialService
|
from langflow.services.credentials.service import CredentialService
|
||||||
from langflow.services.database.service import DatabaseService
|
from langflow.services.database.service import DatabaseService
|
||||||
|
|
@ -16,11 +18,10 @@ if TYPE_CHECKING:
|
||||||
from langflow.services.storage.service import StorageService
|
from langflow.services.storage.service import StorageService
|
||||||
from langflow.services.store.service import StoreService
|
from langflow.services.store.service import StoreService
|
||||||
from langflow.services.task.service import TaskService
|
from langflow.services.task.service import TaskService
|
||||||
from sqlmodel import Session
|
|
||||||
|
|
||||||
|
|
||||||
def get_socket_service() -> "SocketIOService":
|
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":
|
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:
|
if TYPE_CHECKING:
|
||||||
from langflow.services.base import Service
|
from langflow.services.base import Service
|
||||||
|
|
||||||
|
|
||||||
class ServiceFactory:
|
class ServiceFactory:
|
||||||
def __init__(self, service_class):
|
def __init__(
|
||||||
|
self,
|
||||||
|
service_class,
|
||||||
|
):
|
||||||
self.service_class = 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":
|
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
|
from loguru import logger
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from langflow.services.base import Service
|
from langflow.services.base import Service
|
||||||
from langflow.services.factory import ServiceFactory
|
from langflow.services.factory import ServiceFactory
|
||||||
|
from langflow.services.schema import ServiceType
|
||||||
|
|
||||||
|
|
||||||
class ServiceManager:
|
class ServiceManager:
|
||||||
|
|
@ -16,23 +16,19 @@ class ServiceManager:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.services: Dict[str, "Service"] = {}
|
self.services: Dict[str, "Service"] = {}
|
||||||
self.factories = {}
|
self.factories = {}
|
||||||
self.dependencies = {}
|
|
||||||
|
|
||||||
def register_factory(
|
def register_factory(
|
||||||
self,
|
self,
|
||||||
service_factory: "ServiceFactory",
|
service_factory: "ServiceFactory",
|
||||||
dependencies: Optional[List[ServiceType]] = None,
|
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
Registers a new factory with dependencies.
|
Registers a new factory with dependencies.
|
||||||
"""
|
"""
|
||||||
if dependencies is None:
|
|
||||||
dependencies = []
|
|
||||||
service_name = service_factory.service_class.name
|
service_name = service_factory.service_class.name
|
||||||
self.factories[service_name] = service_factory
|
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.
|
Get (or create) a service by its name.
|
||||||
"""
|
"""
|
||||||
|
|
@ -41,7 +37,7 @@ class ServiceManager:
|
||||||
|
|
||||||
return self.services[service_name]
|
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.
|
Create a new service given its name, handling dependencies.
|
||||||
"""
|
"""
|
||||||
|
|
@ -49,25 +45,32 @@ class ServiceManager:
|
||||||
self._validate_service_creation(service_name)
|
self._validate_service_creation(service_name)
|
||||||
|
|
||||||
# Create dependencies first
|
# 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:
|
if dependency not in self.services:
|
||||||
self._create_service(dependency)
|
self._create_service(dependency)
|
||||||
|
|
||||||
# Collect the dependent services
|
# 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
|
# 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()
|
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.
|
Validate whether the service can be created.
|
||||||
"""
|
"""
|
||||||
if service_name not in self.factories:
|
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.
|
Update a service by its name.
|
||||||
"""
|
"""
|
||||||
|
|
@ -90,36 +93,11 @@ class ServiceManager:
|
||||||
logger.exception(exc)
|
logger.exception(exc)
|
||||||
self.services = {}
|
self.services = {}
|
||||||
self.factories = {}
|
self.factories = {}
|
||||||
self.dependencies = {}
|
|
||||||
|
|
||||||
|
|
||||||
service_manager = ServiceManager()
|
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():
|
def initialize_settings_service():
|
||||||
"""
|
"""
|
||||||
Initialize the settings manager.
|
Initialize the settings manager.
|
||||||
|
|
@ -134,13 +112,12 @@ def initialize_session_service():
|
||||||
Initialize the session manager.
|
Initialize the session manager.
|
||||||
"""
|
"""
|
||||||
from langflow.services.cache import factory as cache_factory
|
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()
|
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(
|
service_manager.register_factory(session_service_factory.SessionServiceFactory())
|
||||||
session_service_factory.SessionServiceFactory(),
|
|
||||||
dependencies=[ServiceType.CACHE_SERVICE],
|
|
||||||
)
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
from langflow.services.factory import ServiceFactory
|
from langflow.services.factory import ServiceFactory
|
||||||
from langflow.services.monitor.service import MonitorService
|
from langflow.services.monitor.service import MonitorService
|
||||||
|
from langflow.services.schema import ServiceType
|
||||||
|
|
||||||
|
|
||||||
class MonitorServiceFactory(ServiceFactory):
|
class MonitorServiceFactory(ServiceFactory):
|
||||||
|
|
|
||||||
|
|
@ -14,9 +14,9 @@ class ServiceType(str, Enum):
|
||||||
CHAT_SERVICE = "chat_service"
|
CHAT_SERVICE = "chat_service"
|
||||||
SESSION_SERVICE = "session_service"
|
SESSION_SERVICE = "session_service"
|
||||||
TASK_SERVICE = "task_service"
|
TASK_SERVICE = "task_service"
|
||||||
PLUGIN_SERVICE = "plugin_service"
|
PLUGINS_SERVICE = "plugins_service"
|
||||||
STORE_SERVICE = "store_service"
|
STORE_SERVICE = "store_service"
|
||||||
CREDENTIAL_SERVICE = "credential_service"
|
CREDENTIALS_SERVICE = "credentials_service"
|
||||||
STORAGE_SERVICE = "storage_service"
|
STORAGE_SERVICE = "storage_service"
|
||||||
MONITOR_SERVICE = "monitor_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 typing import TYPE_CHECKING
|
||||||
from langflow.services.session.service import SessionService
|
|
||||||
from langflow.services.factory import ServiceFactory
|
from langflow.services.factory import ServiceFactory
|
||||||
|
from langflow.services.session.service import SessionService
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from langflow.services.cache.service import BaseCacheService
|
from langflow.services.cache.service import CacheService
|
||||||
|
|
||||||
|
|
||||||
class SessionServiceFactory(ServiceFactory):
|
class SessionServiceFactory(ServiceFactory):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super().__init__(SessionService)
|
super().__init__(SessionService)
|
||||||
|
|
||||||
def create(self, cache_service: "BaseCacheService"):
|
def create(self, cache_service: "CacheService"):
|
||||||
return SessionService(cache_service)
|
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
|
from langflow.services.session.utils import compute_dict_hash, session_id_generator
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from langflow.services.cache.base import BaseCacheService
|
from langflow.services.cache.base import CacheService
|
||||||
|
|
||||||
|
|
||||||
class SessionService(Service):
|
class SessionService(Service):
|
||||||
name = "session_service"
|
name = "session_service"
|
||||||
|
|
||||||
def __init__(self, cache_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):
|
async def load_session(self, key, flow_id: str, data_graph: Optional[dict] = None):
|
||||||
# Check if the data is cached
|
# Check if the data is cached
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,18 @@
|
||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
from langflow.services.factory import ServiceFactory
|
from langflow.services.factory import ServiceFactory
|
||||||
|
from langflow.services.schema import ServiceType
|
||||||
from langflow.services.socket.service import SocketIOService
|
from langflow.services.socket.service import SocketIOService
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from langflow.services.cache.service import BaseCacheService
|
from langflow.services.cache.service import CacheService
|
||||||
|
|
||||||
|
|
||||||
class SocketIOFactory(ServiceFactory):
|
class SocketIOFactory(ServiceFactory):
|
||||||
def __init__(self):
|
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)
|
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
|
from langflow.services.socket.utils import build_vertex, get_vertices
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from langflow.services.cache.service import BaseCacheService
|
from langflow.services.cache.service import CacheService
|
||||||
|
|
||||||
|
|
||||||
class SocketIOService(Service):
|
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
|
self.cache_service = cache_service
|
||||||
|
|
||||||
def init(self, sio: socketio.AsyncServer):
|
def init(self, sio: socketio.AsyncServer):
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
from langflow.services.factory import ServiceFactory
|
from langflow.services.factory import ServiceFactory
|
||||||
|
from langflow.services.schema import ServiceType
|
||||||
from langflow.services.storage.service import StorageService
|
from langflow.services.storage.service import StorageService
|
||||||
from loguru import logger
|
from loguru import logger
|
||||||
|
|
||||||
|
|
@ -11,9 +12,13 @@ if TYPE_CHECKING:
|
||||||
|
|
||||||
class StorageServiceFactory(ServiceFactory):
|
class StorageServiceFactory(ServiceFactory):
|
||||||
def __init__(self):
|
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
|
storage_type = settings_service.settings.STORAGE_TYPE
|
||||||
if storage_type.lower() == "local":
|
if storage_type.lower() == "local":
|
||||||
from .local import LocalStorageService
|
from .local import LocalStorageService
|
||||||
|
|
@ -24,7 +29,9 @@ class StorageServiceFactory(ServiceFactory):
|
||||||
|
|
||||||
return S3StorageService(session_service, settings_service)
|
return S3StorageService(session_service, settings_service)
|
||||||
else:
|
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
|
from .local import LocalStorageService
|
||||||
|
|
||||||
return LocalStorageService(session_service, settings_service)
|
return LocalStorageService(session_service, settings_service)
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,12 @@
|
||||||
|
import importlib
|
||||||
|
import inspect
|
||||||
|
|
||||||
from loguru import logger
|
from loguru import logger
|
||||||
from sqlmodel import Session, select
|
from sqlmodel import Session, select
|
||||||
|
|
||||||
from langflow.services.auth.utils import create_super_user, verify_password
|
from langflow.services.auth.utils import create_super_user, verify_password
|
||||||
from langflow.services.database.utils import initialize_database
|
from langflow.services.database.utils import initialize_database
|
||||||
|
from langflow.services.factory import ServiceFactory
|
||||||
from langflow.services.manager import service_manager
|
from langflow.services.manager import service_manager
|
||||||
from langflow.services.schema import ServiceType
|
from langflow.services.schema import ServiceType
|
||||||
from langflow.services.settings.constants import (
|
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
|
from .deps import get_db_service, get_session, get_settings_service
|
||||||
|
|
||||||
|
|
||||||
def get_factories_and_deps():
|
def get_factories():
|
||||||
from langflow.services.auth import factory as auth_factory
|
service_names = [
|
||||||
from langflow.services.cache import factory as cache_factory
|
ServiceType(service_type).value.replace("_service", "")
|
||||||
from langflow.services.chat import factory as chat_factory
|
for service_type in ServiceType
|
||||||
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]),
|
|
||||||
]
|
]
|
||||||
|
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):
|
def get_or_create_super_user(session: Session, username, password, is_default):
|
||||||
|
|
@ -198,11 +178,12 @@ def initialize_session_service():
|
||||||
|
|
||||||
initialize_settings_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(
|
service_manager.register_factory(
|
||||||
session_service_factory.SessionServiceFactory(),
|
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.
|
Initialize all the services needed.
|
||||||
"""
|
"""
|
||||||
for factory, dependencies in get_factories_and_deps():
|
for factory in get_factories():
|
||||||
try:
|
try:
|
||||||
service_manager.register_factory(factory, dependencies=dependencies)
|
service_manager.register_factory(factory)
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
logger.exception(exc)
|
logger.exception(exc)
|
||||||
raise RuntimeError("Could not initialize services. Please check your settings.") from exc
|
raise RuntimeError("Could not initialize services. Please check your settings.") from exc
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue