---
title: serving_engine
---

<div class="python-reference">
<a id="fastvideo.entrypoints.openai.serving_engine-classes"></a>
<a id="fastvideo.entrypoints.openai.serving_engine.OpenAIServingEngine-functions"></a>
<a id="fastvideo.entrypoints.openai.serving_engine"></a>
<p>Shared asynchronous execution substrate for OpenAI-compatible routes.</p>
<h2 id="fastvideo.entrypoints.openai.serving_engine.GenerationRequest"><code>fastvideo.entrypoints.openai.serving_engine.GenerationRequest</code></h2>
<pre class="doc-signature"><code>GenerationRequest(prompt: str | list&#91;str&#93; | None = None, negative_prompt: str | None = None, inputs: InputConfig = InputConfig(), sampling: SamplingConfig = SamplingConfig(), runtime: RequestRuntimeConfig = RequestRuntimeConfig(), output: OutputConfig = OutputConfig(), stage_overrides: dict&#91;str, Any&#93; = dict(), state: ContinuationState | None = None, plan: GenerationPlan | None = None, extensions: dict&#91;str, Any&#93; = dict())</code></pre>


<h2 id="fastvideo.entrypoints.openai.serving_engine.VideoGenerationRequest"><code>fastvideo.entrypoints.openai.serving_engine.VideoGenerationRequest</code></h2>
<pre class="doc-signature"><code>VideoGenerationRequest()</code></pre>
<p>OpenAI/vLLM-Omni-compatible video generation request.</p>
<p>Model-specific parameters belong in <code>extra_params</code>. FastVideo keeps the
legacy <code>input_reference</code> and <code>reference_url</code> fields for clients that
predate vLLM-Omni's typed reference objects.</p>
<h3 id="fastvideo.entrypoints.openai.serving_engine.VideoGenerationRequest.validate_prompt"><code>fastvideo.entrypoints.openai.serving_engine.VideoGenerationRequest.validate_prompt</code></h3>
<pre class="doc-signature"><code>validate_prompt(value: str) -&gt; str</code></pre>

<h3 id="fastvideo.entrypoints.openai.serving_engine.VideoGenerationRequest.resolve_video_params"><code>fastvideo.entrypoints.openai.serving_engine.VideoGenerationRequest.resolve_video_params</code></h3>
<pre class="doc-signature"><code>resolve_video_params() -&gt; VideoParams</code></pre>
<p>Resolve top-level, nested, and <code>size</code> dimensions like vLLM-Omni.</p>
<h2 id="fastvideo.entrypoints.openai.serving_engine.ServingGenerator"><code>fastvideo.entrypoints.openai.serving_engine.ServingGenerator</code></h2>
<pre class="doc-signature"><code>ServingGenerator()</code></pre>

<details><summary>Source</summary><pre><code>class ServingGenerator(Protocol):

    def generate(self, request: GenerationRequest) -&gt; Any:
        ...

    def shutdown(self) -&gt; None:
        ...</code></pre></details>
<h3 id="fastvideo.entrypoints.openai.serving_engine.ServingGenerator.generate"><code>fastvideo.entrypoints.openai.serving_engine.ServingGenerator.generate</code></h3>
<pre class="doc-signature"><code>generate(request: GenerationRequest) -&gt; Any</code></pre>

<details><summary>Source</summary><pre><code>def generate(self, request: GenerationRequest) -&gt; Any:
    ...</code></pre></details>
<h3 id="fastvideo.entrypoints.openai.serving_engine.ServingGenerator.shutdown"><code>fastvideo.entrypoints.openai.serving_engine.ServingGenerator.shutdown</code></h3>
<pre class="doc-signature"><code>shutdown() -&gt; None</code></pre>

<details><summary>Source</summary><pre><code>def shutdown(self) -&gt; None:
    ...</code></pre></details>
<h2 id="fastvideo.entrypoints.openai.serving_engine.OpenAIServingEngine"><code>fastvideo.entrypoints.openai.serving_engine.OpenAIServingEngine</code></h2>
<pre class="doc-signature"><code>OpenAIServingEngine(generator: ServingGenerator, video_request_validator: Callable&#91;&#91;VideoGenerationRequest&#93;, None&#93; | None = None)</code></pre>
<p>Own generator lifecycle and serialize access to its mutable pipeline.</p>
<p>FastVideo pipelines contain request-mutated sampling state and some LoRA
implementations merge weights in place. Running two Python threads through
one pipeline is therefore unsafe even if the HTTP layer accepts requests
concurrently. This engine gives every OpenAI route one model-agnostic async
entrypoint while preserving that invariant. A future scheduler can replace
the lock without changing the transport contract.</p>

<details><summary>Source</summary><pre><code>class OpenAIServingEngine:
    &quot;&quot;&quot;Own generator lifecycle and serialize access to its mutable pipeline.

    FastVideo pipelines contain request-mutated sampling state and some LoRA
    implementations merge weights in place. Running two Python threads through
    one pipeline is therefore unsafe even if the HTTP layer accepts requests
    concurrently. This engine gives every OpenAI route one model-agnostic async
    entrypoint while preserving that invariant. A future scheduler can replace
    the lock without changing the transport contract.
    &quot;&quot;&quot;

    def __init__(self,
                 generator: ServingGenerator,
                 video_request_validator: Callable&#91;&#91;VideoGenerationRequest&#93;, None&#93; | None = None) -&gt; None:
        self._generator = generator
        self._video_request_validator = video_request_validator
        self._generation_lock = asyncio.Lock()
        self._closed = False
        self._unhealthy_reason: str | None = None

    @property
    def generator(self) -&gt; ServingGenerator:
        return self._generator

    def validate_video_request(self, request: VideoGenerationRequest) -&gt; None:
        if self._video_request_validator is not None:
            self._video_request_validator(request)

    @property
    def closed(self) -&gt; bool:
        return self._closed

    @property
    def healthy(self) -&gt; bool:
        if self._closed or self._unhealthy_reason is not None:
            return False
        executor = getattr(self._generator, &quot;executor&quot;, None)
        workers = getattr(executor, &quot;workers&quot;, None)
        if workers is None:
            return True
        return bool(workers) and all(worker.proc.is_alive() for worker in workers)

    @property
    def unhealthy_reason(self) -&gt; str | None:
        if self._unhealthy_reason is not None:
            return self._unhealthy_reason
        if not self.healthy:
            return &quot;one or more generation workers are not alive&quot;
        return None

    async def generate(
        self,
        request: GenerationRequest,
        *,
        on_start: Callable&#91;&#91;&#93;, Awaitable&#91;None&#93;&#93; | None = None,
    ) -&gt; Any:
        &quot;&quot;&quot;Generate one typed request without blocking the event loop.&quot;&quot;&quot;
        return await self.run_serialized(self._generator.generate, request, on_start=on_start)

    async def run_serialized(
        self,
        function: Callable&#91;..., _T&#93;,
        *args: Any,
        on_start: Callable&#91;&#91;&#93;, Awaitable&#91;None&#93;&#93; | None = None,
        **kwargs: Any,
    ) -&gt; _T:
        &quot;&quot;&quot;Run a synchronous pipeline operation under the serving lock.&quot;&quot;&quot;
        if self._closed:
            raise RuntimeError(&quot;FastVideo serving engine is shutting down&quot;)
        async with self._generation_lock:
            if self._closed:
                raise RuntimeError(&quot;FastVideo serving engine is shutting down&quot;)
            if on_start is not None:
                await on_start()
            worker = asyncio.create_task(asyncio.to_thread(function, *args, **kwargs))
            try:
                return await asyncio.shield(worker)
            except asyncio.CancelledError:
                # Python cannot stop a running worker thread. Keep the lock
                # until the pipeline call really exits so cancellation cannot
                # expose mutable model state to a second request.
                await self._wait_after_cancellation(worker)
                raise
            except (BrokenPipeError, EOFError) as error:
                self._unhealthy_reason = str(error)
                raise

    async def run_async_serialized(self, function: Callable&#91;&#91;&#93;, Awaitable&#91;_T&#93;&#93;) -&gt; _T:
        &quot;&quot;&quot;Run an async operation under the same pipeline lock.&quot;&quot;&quot;
        if self._closed:
            raise RuntimeError(&quot;FastVideo serving engine is shutting down&quot;)
        async with self._generation_lock:
            if self._closed:
                raise RuntimeError(&quot;FastVideo serving engine is shutting down&quot;)
            worker: asyncio.Future&#91;_T&#93; = asyncio.ensure_future(function())
            try:
                return await asyncio.shield(worker)
            except asyncio.CancelledError:
                await self._wait_after_cancellation(worker)
                raise

    @staticmethod
    async def _wait_after_cancellation(worker: asyncio.Future&#91;Any&#93;) -&gt; None:
        &quot;&quot;&quot;Keep waiting for an uninterruptible worker despite repeated cancellation.&quot;&quot;&quot;
        while not worker.done():
            try:
                await asyncio.shield(worker)
            except asyncio.CancelledError:
                continue
            except Exception:
                break
        if not worker.cancelled():
            worker.exception()

    async def shutdown(self) -&gt; None:
        &quot;&quot;&quot;Stop accepting requests and release the generator after in-flight work.&quot;&quot;&quot;
        self._closed = True
        async with self._generation_lock:
            await asyncio.to_thread(self._generator.shutdown)</code></pre></details>
<h3 id="fastvideo.entrypoints.openai.serving_engine.OpenAIServingEngine.validate_video_request"><code>fastvideo.entrypoints.openai.serving_engine.OpenAIServingEngine.validate_video_request</code></h3>
<pre class="doc-signature"><code>validate_video_request(request: VideoGenerationRequest) -&gt; None</code></pre>

<details><summary>Source</summary><pre><code>def validate_video_request(self, request: VideoGenerationRequest) -&gt; None:
    if self._video_request_validator is not None:
        self._video_request_validator(request)</code></pre></details>
<h3 id="fastvideo.entrypoints.openai.serving_engine.OpenAIServingEngine.generate"><code>fastvideo.entrypoints.openai.serving_engine.OpenAIServingEngine.generate</code></h3>
<pre class="doc-signature"><code>generate(request: GenerationRequest, *, on_start: Callable&#91;&#91;&#93;, Awaitable&#91;None&#93;&#93; | None = None) -&gt; Any</code></pre>
<p>Generate one typed request without blocking the event loop.</p>
<details><summary>Source</summary><pre><code>async def generate(
    self,
    request: GenerationRequest,
    *,
    on_start: Callable&#91;&#91;&#93;, Awaitable&#91;None&#93;&#93; | None = None,
) -&gt; Any:
    &quot;&quot;&quot;Generate one typed request without blocking the event loop.&quot;&quot;&quot;
    return await self.run_serialized(self._generator.generate, request, on_start=on_start)</code></pre></details>
<h3 id="fastvideo.entrypoints.openai.serving_engine.OpenAIServingEngine.run_serialized"><code>fastvideo.entrypoints.openai.serving_engine.OpenAIServingEngine.run_serialized</code></h3>
<pre class="doc-signature"><code>run_serialized(function: Callable&#91;..., _T&#93;, *args: Any, on_start: Callable&#91;&#91;&#93;, Awaitable&#91;None&#93;&#93; | None = None, **kwargs: Any) -&gt; _T</code></pre>
<p>Run a synchronous pipeline operation under the serving lock.</p>
<details><summary>Source</summary><pre><code>async def run_serialized(
    self,
    function: Callable&#91;..., _T&#93;,
    *args: Any,
    on_start: Callable&#91;&#91;&#93;, Awaitable&#91;None&#93;&#93; | None = None,
    **kwargs: Any,
) -&gt; _T:
    &quot;&quot;&quot;Run a synchronous pipeline operation under the serving lock.&quot;&quot;&quot;
    if self._closed:
        raise RuntimeError(&quot;FastVideo serving engine is shutting down&quot;)
    async with self._generation_lock:
        if self._closed:
            raise RuntimeError(&quot;FastVideo serving engine is shutting down&quot;)
        if on_start is not None:
            await on_start()
        worker = asyncio.create_task(asyncio.to_thread(function, *args, **kwargs))
        try:
            return await asyncio.shield(worker)
        except asyncio.CancelledError:
            # Python cannot stop a running worker thread. Keep the lock
            # until the pipeline call really exits so cancellation cannot
            # expose mutable model state to a second request.
            await self._wait_after_cancellation(worker)
            raise
        except (BrokenPipeError, EOFError) as error:
            self._unhealthy_reason = str(error)
            raise</code></pre></details>
<h3 id="fastvideo.entrypoints.openai.serving_engine.OpenAIServingEngine.run_async_serialized"><code>fastvideo.entrypoints.openai.serving_engine.OpenAIServingEngine.run_async_serialized</code></h3>
<pre class="doc-signature"><code>run_async_serialized(function: Callable&#91;&#91;&#93;, Awaitable&#91;_T&#93;&#93;) -&gt; _T</code></pre>
<p>Run an async operation under the same pipeline lock.</p>
<details><summary>Source</summary><pre><code>async def run_async_serialized(self, function: Callable&#91;&#91;&#93;, Awaitable&#91;_T&#93;&#93;) -&gt; _T:
    &quot;&quot;&quot;Run an async operation under the same pipeline lock.&quot;&quot;&quot;
    if self._closed:
        raise RuntimeError(&quot;FastVideo serving engine is shutting down&quot;)
    async with self._generation_lock:
        if self._closed:
            raise RuntimeError(&quot;FastVideo serving engine is shutting down&quot;)
        worker: asyncio.Future&#91;_T&#93; = asyncio.ensure_future(function())
        try:
            return await asyncio.shield(worker)
        except asyncio.CancelledError:
            await self._wait_after_cancellation(worker)
            raise</code></pre></details>
<h3 id="fastvideo.entrypoints.openai.serving_engine.OpenAIServingEngine.shutdown"><code>fastvideo.entrypoints.openai.serving_engine.OpenAIServingEngine.shutdown</code></h3>
<pre class="doc-signature"><code>shutdown() -&gt; None</code></pre>
<p>Stop accepting requests and release the generator after in-flight work.</p>
<details><summary>Source</summary><pre><code>async def shutdown(self) -&gt; None:
    &quot;&quot;&quot;Stop accepting requests and release the generator after in-flight work.&quot;&quot;&quot;
    self._closed = True
    async with self._generation_lock:
        await asyncio.to_thread(self._generator.shutdown)</code></pre></details>
</div>
