Service lifecycle framework with FastAPI background services, dependency management, and optional desktop GUI launcher
Project description
Web App
Service lifecycle framework with FastAPI background services, dependency management, and optional desktop GUI launcher.
Overview
vcti-webapp provides a Service base class for managing background services
with ordered dependencies and thread-safe lifecycle control. FastAPIService
extends this to run FastAPI applications via uvicorn in background threads
with automatic port discovery. For desktop applications, the optional GUI
module adds AppLauncher (pywebview window), StaticDirApp (static file
serving), and ZippedApp (serve from ZIP archives).
Installation
Core (services only):
pip install vcti-webapp>=1.0.0
With desktop GUI support:
pip install vcti-webapp[gui]>=1.0.0
With ZIP archive support (includes GUI + vcti-session):
pip install vcti-webapp[zip]>=1.0.0
Quick Start
Background FastAPI service
from fastapi import FastAPI
from vcti.webapp import FastAPIService
app = FastAPI()
@app.get("/health")
async def health():
return {"status": "ok"}
# Start in background thread with auto-discovered port
with FastAPIService(app, name="api") as svc:
print(f"Running on http://localhost:{svc.port}")
# ... do work ...
# Server stops automatically on exit
Service dependencies
from vcti.webapp import Service, FastAPIService, service_dependency
class DatabaseService(Service):
def _start_service(self):
self.connection = connect_to_db()
def _stop_service(self):
self.connection.close()
db = DatabaseService(name="database")
api = FastAPIService(app, name="api")
api.add_dependency(db)
api.start() # starts db first, then api
api.stop() # stops api first, then db (reverse order)
Error recovery
from vcti.webapp import CyclicDependencyError
# Circular dependencies are caught at registration time
try:
svc_a.add_dependency(svc_b)
except CyclicDependencyError:
print("Would create a cycle — dependency not added")
# Start failures roll back dependencies automatically
try:
svc.start()
except RuntimeError:
# All already-started dependencies have been stopped
print("Service failed to start, deps cleaned up")
Desktop GUI (requires pywebview)
from vcti.webapp.app_launcher import AppLauncher
launcher = AppLauncher(app, window_title="My App", window_size=(1280, 720))
launcher.start() # opens desktop window, blocks until closed
Core API
Service (base)
| Method | Description |
|---|---|
start() |
Start service and dependencies (thread-safe, safe to call from multiple threads) |
stop() |
Stop service and optionally dependencies |
add_dependency(service) |
Register a dependency (returns self, raises CyclicDependencyError on cycle) |
is_running() |
Check if running |
FastAPIService
| Parameter | Default | Description |
|---|---|---|
app |
(required) | The FastAPI application |
host |
"127.0.0.1" |
Bind address (loopback only by default for security) |
port |
None |
TCP port (None = auto-discover a free port) |
ready_timeout |
10.0 |
Seconds to wait for server readiness; 0 to skip |
ready_poll_interval |
0.05 |
Seconds between readiness polls |
uvicorn_config |
None |
Extra kwargs forwarded to uvicorn.Config |
GUI classes (optional — vcti-webapp[gui])
| Class | Purpose |
|---|---|
AppLauncher |
Desktop window via pywebview |
StaticDirApp |
Serve static files from a directory |
ZippedApp |
Extract and serve from ZIP archive |
Advanced Usage
Custom uvicorn configuration
# Suppress noisy startup logs
svc = FastAPIService(app, uvicorn_config={"log_level": "warning", "access_log": False})
# TLS termination at uvicorn
svc = FastAPIService(app, uvicorn_config={
"ssl_keyfile": "key.pem",
"ssl_certfile": "cert.pem",
})
Slow CI environments
# Increase readiness timeout on slow machines
svc = FastAPIService(app, ready_timeout=30.0, ready_poll_interval=0.1)
Shared dependencies
When multiple services share a dependency, use stop_dependencies=False
to prevent the first service to stop from tearing down the shared resource:
db = DatabaseService(name="db")
api = FastAPIService(app, name="api", stop_dependencies=False)
api.add_dependency(db)
worker = WorkerService(name="worker", stop_dependencies=False)
worker.add_dependency(db)
# api.stop() leaves db running — worker still needs it
Static file serving without GUI
StaticDirApp inherits from AppLauncher (which requires pywebview),
but you can serve static files without a GUI using plain FastAPIService:
from fastapi import FastAPI
from fastapi.staticfiles import StaticFiles
from vcti.webapp import FastAPIService
app = FastAPI()
app.mount("/static", StaticFiles(directory="./dist"), name="static")
with FastAPIService(app, name="docs-server") as svc:
print(f"Serving at http://localhost:{svc.port}/static/index.html")
Root redirect (show_index_on_root)
StaticDirApp and ZippedApp redirect GET / to
{static_route}/{default_page} by default. Set show_index_on_root=False
if you define your own root route or want / to return 404:
StaticDirApp(Path("./dist"), show_index_on_root=False)
Threading
start() and stop() are thread-safe. Calling start() from multiple
threads simultaneously is safe — only one thread runs startup; others
return immediately. See docs/design.md for details on
lock ordering and concurrency guarantees.
Dependencies
- fastapi (>=0.100) — required
- uvicorn (>=0.20) — required
- pywebview (>=4.0) — optional, for GUI
- vcti-session (>=1.0.0) — optional, for ZippedApp
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file vcti_webapp-1.0.0.tar.gz.
File metadata
- Download URL: vcti_webapp-1.0.0.tar.gz
- Upload date:
- Size: 18.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
af1f6a1aa85870da1746e186ab7ec1304fb7a5a58e3a68588af84f0437d76260
|
|
| MD5 |
04213a4f319e7b7297381f7acda330d5
|
|
| BLAKE2b-256 |
16a03356626e70e377e8c1a6612728252900b37f6fbe45a27d48836eca04d566
|
Provenance
The following attestation bundles were made for vcti_webapp-1.0.0.tar.gz:
Publisher:
publish.yml on vcollab/vcti-python-webapp
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
vcti_webapp-1.0.0.tar.gz -
Subject digest:
af1f6a1aa85870da1746e186ab7ec1304fb7a5a58e3a68588af84f0437d76260 - Sigstore transparency entry: 1194126840
- Sigstore integration time:
-
Permalink:
vcollab/vcti-python-webapp@f285e6a7ce49fbdc0ef60e406b57e4824e982e43 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/vcollab
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@f285e6a7ce49fbdc0ef60e406b57e4824e982e43 -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file vcti_webapp-1.0.0-py3-none-any.whl.
File metadata
- Download URL: vcti_webapp-1.0.0-py3-none-any.whl
- Upload date:
- Size: 13.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5c3ee45fc9908f2f8396a71acf57b1a6ac748698b5f840979a67b8e8866fd26a
|
|
| MD5 |
33b61811192868e4bbd518348dff397a
|
|
| BLAKE2b-256 |
c0f2e86255f83aba85a98763709f91c35ed071616e4b74ab4c1112f132c16223
|
Provenance
The following attestation bundles were made for vcti_webapp-1.0.0-py3-none-any.whl:
Publisher:
publish.yml on vcollab/vcti-python-webapp
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
vcti_webapp-1.0.0-py3-none-any.whl -
Subject digest:
5c3ee45fc9908f2f8396a71acf57b1a6ac748698b5f840979a67b8e8866fd26a - Sigstore transparency entry: 1194126842
- Sigstore integration time:
-
Permalink:
vcollab/vcti-python-webapp@f285e6a7ce49fbdc0ef60e406b57e4824e982e43 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/vcollab
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@f285e6a7ce49fbdc0ef60e406b57e4824e982e43 -
Trigger Event:
workflow_dispatch
-
Statement type: