Skip to content

Zen Service

zenml.zen_service special

Zen Service

The Zen Service is a simple webserver to let you collaborate on stacks via the network. It can be spun up in a background daemon from the command line using zenml service up and managed from the same command line group.

Using the Zen Service's stacks in your project just requires setting up a profile with rest store-type pointed to the url of the service.

zen_service

ZenService (LocalDaemonService) pydantic-model

ZenService daemon that can be used to start a local ZenService server.

Attributes:

Name Type Description
config ZenServiceConfig

service configuration

endpoint ZenServiceEndpoint

optional service endpoint

Source code in zenml/zen_service/zen_service.py
class ZenService(LocalDaemonService):
    """ZenService daemon that can be used to start a local ZenService server.

    Attributes:
        config: service configuration
        endpoint: optional service endpoint
    """

    SERVICE_TYPE = ServiceType(
        name="zen_service",
        type="zenml",
        flavor="zenml",
        description="ZenService to manage stacks, user and pipelines",
    )

    config: ZenServiceConfig
    endpoint: ZenServiceEndpoint

    def __init__(
        self,
        config: Union[ZenServiceConfig, Dict[str, Any]],
        **attrs: Any,
    ) -> None:
        # ensure that the endpoint is created before the service is initialized
        if isinstance(config, ZenServiceConfig) and "endpoint" not in attrs:

            endpoint_uri_path = ZEN_SERVICE_URL_PATH
            healthcheck_uri_path = ZEN_SERVICE_HEALTHCHECK_URL_PATH
            use_head_request = True

            endpoint = ZenServiceEndpoint(
                config=ZenServiceEndpointConfig(
                    protocol=ServiceEndpointProtocol.HTTP,
                    port=config.port,
                    zen_service_uri_path=endpoint_uri_path,
                ),
                monitor=HTTPEndpointHealthMonitor(
                    config=HTTPEndpointHealthMonitorConfig(
                        healthcheck_uri_path=healthcheck_uri_path,
                        use_head_request=use_head_request,
                    )
                ),
            )
            attrs["endpoint"] = endpoint
        super().__init__(config=config, **attrs)

    def run(self) -> None:
        if self.config.store_profile_configuration.store_type == StoreType.REST:
            raise ValueError(
                "Service cannot be started with REST store type. Make sure you "
                "specify a profile with a non-networked persistence backend "
                "when trying to start the Zen Service. (use command line flag "
                "`--profile=$PROFILE_NAME` or set the env variable "
                f"{ENV_ZENML_PROFILE_NAME} to specify the use of a profile "
                "other than the currently active one)"
            )
        logger.info(
            "Starting ZenService as blocking "
            "process... press CTRL+C once to stop it."
        )

        self.endpoint.prepare_for_start()

        # this is the only way to pass information into the FastAPI app??
        os.environ[
            "ZENML_PROFILE_CONFIGURATION"
        ] = self.config.store_profile_configuration.json()

        try:
            uvicorn.run(
                "zenml.zen_service.zen_service_api:app",
                host="127.0.0.1",
                port=self.endpoint.status.port,
                log_level="info",
            )
        except KeyboardInterrupt:
            logger.info("Zen service stopped. Resuming normal execution.")

    @property
    def zen_service_uri(self) -> Optional[str]:
        """Get the URI where the service is running.

        Returns:
            The URI where the service can be contacted for requests,
             or None, if the service isn't running.
        """
        if not self.is_running:
            return None
        return self.endpoint.endpoint_uri
zen_service_uri: Optional[str] property readonly

Get the URI where the service is running.

Returns:

Type Description
Optional[str]

The URI where the service can be contacted for requests, or None, if the service isn't running.

run(self)

Run the service daemon process associated with this service.

Subclasses must implement this method to provide the service daemon functionality. This method will be executed in the context of the running daemon, not in the context of the process that calls the start method.

Source code in zenml/zen_service/zen_service.py
def run(self) -> None:
    if self.config.store_profile_configuration.store_type == StoreType.REST:
        raise ValueError(
            "Service cannot be started with REST store type. Make sure you "
            "specify a profile with a non-networked persistence backend "
            "when trying to start the Zen Service. (use command line flag "
            "`--profile=$PROFILE_NAME` or set the env variable "
            f"{ENV_ZENML_PROFILE_NAME} to specify the use of a profile "
            "other than the currently active one)"
        )
    logger.info(
        "Starting ZenService as blocking "
        "process... press CTRL+C once to stop it."
    )

    self.endpoint.prepare_for_start()

    # this is the only way to pass information into the FastAPI app??
    os.environ[
        "ZENML_PROFILE_CONFIGURATION"
    ] = self.config.store_profile_configuration.json()

    try:
        uvicorn.run(
            "zenml.zen_service.zen_service_api:app",
            host="127.0.0.1",
            port=self.endpoint.status.port,
            log_level="info",
        )
    except KeyboardInterrupt:
        logger.info("Zen service stopped. Resuming normal execution.")

ZenServiceConfig (LocalDaemonServiceConfig) pydantic-model

Zen Service deployment configuration.

Attributes:

Name Type Description
port int

Port at which the service is running

store_profile_configuration ProfileConfiguration

ProfileConfiguration describing where the service should persist its data.

Source code in zenml/zen_service/zen_service.py
class ZenServiceConfig(LocalDaemonServiceConfig):
    """Zen Service deployment configuration.

    Attributes:
        port: Port at which the service is running
        store_profile_configuration: ProfileConfiguration describing where
            the service should persist its data.
    """

    port: int = 8000
    store_profile_configuration: ProfileConfiguration = Field(
        default_factory=lambda: Repository().active_profile
    )

ZenServiceEndpoint (LocalDaemonServiceEndpoint) pydantic-model

A service endpoint exposed by the Zen service daemon.

Attributes:

Name Type Description
config ZenServiceEndpointConfig

service endpoint configuration

monitor HTTPEndpointHealthMonitor

optional service endpoint health monitor

Source code in zenml/zen_service/zen_service.py
class ZenServiceEndpoint(LocalDaemonServiceEndpoint):
    """A service endpoint exposed by the Zen service daemon.

    Attributes:
        config: service endpoint configuration
        monitor: optional service endpoint health monitor
    """

    config: ZenServiceEndpointConfig
    monitor: HTTPEndpointHealthMonitor

    @property
    def endpoint_uri(self) -> Optional[str]:
        uri = self.status.uri
        if not uri:
            return None
        return f"{uri}{self.config.zen_service_uri_path}"

ZenServiceEndpointConfig (LocalDaemonServiceEndpointConfig) pydantic-model

Zen Service endpoint configuration.

Attributes:

Name Type Description
zen_service_uri_path str

URI path for the zenml service

Source code in zenml/zen_service/zen_service.py
class ZenServiceEndpointConfig(LocalDaemonServiceEndpointConfig):
    """Zen Service endpoint configuration.

    Attributes:
        zen_service_uri_path: URI path for the zenml service
    """

    zen_service_uri_path: str

zen_service_api

conflict(error)

Convert an Exception to a HTTP 404 response.

Source code in zenml/zen_service/zen_service_api.py
def conflict(error: Exception) -> HTTPException:
    """Convert an Exception to a HTTP 404 response."""
    return HTTPException(status_code=409, detail=error_detail(error))

error_detail(error)

Convert an Exception to API representation.

Source code in zenml/zen_service/zen_service_api.py
def error_detail(error: Exception) -> List[str]:
    """Convert an Exception to API representation."""
    return [type(error).__name__] + [str(a) for a in error.args]

not_found(error)

Convert an Exception to a HTTP 404 response.

Source code in zenml/zen_service/zen_service_api.py
def not_found(error: Exception) -> HTTPException:
    """Convert an Exception to a HTTP 404 response."""
    return HTTPException(status_code=404, detail=error_detail(error))