Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1,961 changes: 38 additions & 1,923 deletions bluesky_queueserver/manager/plan_queue_ops.py

Large diffs are not rendered by default.

89 changes: 89 additions & 0 deletions bluesky_queueserver/manager/plan_queue_ops_backends/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
"""
Plan Queue Operations Backend Implementations.

This package contains the various backend implementations for the Plan Queue Operations:
- Redis: Uses Redis as the backend storage
- SQLite: Uses SQLite database as the backend storage
- PostgreSQL: Uses PostgreSQL database as the backend storage
- Dict: Uses an in-memory dictionary (optionally persisted to file) as the backend storage
"""
import os

# Dictionary mapping backend names to their import paths
_BACKENDS = {
"abstract": ".plan_queue_ops_abstract.AbstractPlanQueueOperations",
"redis": ".plan_queue_ops_redis.RedisPlanQueueOperations",
"sqlite": ".plan_queue_ops_sqlite.SQLitePlanQueueOperations",
"dict": ".plan_queue_ops_dict.DictPlanQueueOperations",
"postgresql": ".plan_queue_ops_postgresql.PostgreSQLPlanQueueOperations",
}

def get_backend(backend_name=None):
"""
Dynamically import and return the requested backend class.

Parameters
----------
backend_name : str, optional
Name of the backend ('redis', 'sqlite', 'dict', 'postgresql')
If None, will look for PLAN_QUEUE_BACKEND environment variable,
and default to 'redis' if not found.

Returns
-------
class
The requested backend class

Raises
------
ValueError
If the backend name is not recognized
ImportError
If the backend cannot be imported (e.g., missing dependencies)
"""
# If no backend specified, check environment variable
if backend_name is None:
backend_name = os.getenv("PLAN_QUEUE_BACKEND", "redis").lower()

if backend_name not in _BACKENDS:
raise ValueError(f"Unknown backend: {backend_name}. Available backends: {list(_BACKENDS.keys())}")

import importlib
module_path, class_name = _BACKENDS[backend_name].rsplit('.', 1)
module = importlib.import_module(module_path, package=__package__)
return getattr(module, class_name)

def get_default_backend():
"""
Get the default backend class based on PLAN_QUEUE_BACKEND environment variable.
Defaults to Redis if no environment variable is set.

Returns
-------
class
The default backend class
"""
return get_backend()

# For compatibility with old code that expects direct imports
def __getattr__(name):
"""
Support for direct attribute access like:
from plan_queue_ops_backends import RedisPlanQueueOperations
"""
# Map class names to backend names
class_to_backend = {
"AbstractPlanQueueOperations": "abstract",
"RedisPlanQueueOperations": "redis",
"SQLitePlanQueueOperations": "sqlite",
"DictPlanQueueOperations": "dict",
"PostgreSQLPlanQueueOperations": "postgresql",
}

if name in class_to_backend:
try:
return get_backend(class_to_backend[name])
except ImportError:
raise ImportError(f"Could not import {name} - backend dependencies may be missing")

raise AttributeError(f"module {__name__} has no attribute {name}")
94 changes: 94 additions & 0 deletions bluesky_queueserver/manager/plan_queue_ops_backends/config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
"""
Configuration settings for Plan Queue Operation backends.

This module contains default configuration values for all supported backends.
These settings can be overridden by passing keyword arguments to the backend constructors.
"""

import os

# Common configuration shared by all backends
COMMON_CONFIG = {
"name_prefix": "qs_default", # Prefix for database tables/keys
}

# Redis backend configuration
REDIS_CONFIG = {
"host": "localhost",
"port": 6379,
"db": 0,
"password": None,
"name_prefix": COMMON_CONFIG["name_prefix"],
"decode_responses": True, # Essential for proper string handling
}

# SQLite backend configuration
SQLITE_CONFIG = {
"database": os.path.join(os.getcwd(), "queue_storage.sqlite"),
"timeout": 5.0, # Connection timeout in seconds
"detect_types": 0,
"isolation_level": None, # Autocommit mode
"check_same_thread": False, # Allow access from multiple threads
"name_prefix": COMMON_CONFIG["name_prefix"],
}

# PostgreSQL backend configuration
POSTGRESQL_CONFIG = {
"host": "localhost",
"port": 5432,
"database": "bluesky_queue",
"user": "postgres",
"password": "postgres",
"min_size": 1, # Minimum connection pool size
"max_size": 10, # Maximum connection pool size
"timeout": 10.0, # Connection timeout in seconds
"name_prefix": COMMON_CONFIG["name_prefix"],
}

# Dict backend configuration (in-memory Python dictionary, optionally backed by file)
DICT_CONFIG = {
"in_memory": False, # Whether to use in-memory only or persist to file
"storage_file": None, # Path to storage file (if None, uses default based on name_prefix)
"name_prefix": COMMON_CONFIG["name_prefix"],
"autosave": True, # Whether to automatically save changes to file
"autosave_interval": 1.0, # Seconds between autosaves (if autosave is enabled)
}

# Backend selection
DEFAULT_BACKEND = "redis" # Default backend if not specified in environment

def get_backend_config(backend_name=None):
"""
Get configuration for the specified backend.

Parameters
----------
backend_name : str, optional
Name of the backend ('redis', 'sqlite', 'postgresql', 'dict')
If None, get from PLAN_QUEUE_BACKEND environment variable or default

Returns
-------
dict
Configuration dictionary for the specified backend

Raises
------
ValueError
If the backend name is not recognized
"""
# Determine backend name
if backend_name is None:
backend_name = os.getenv("PLAN_QUEUE_BACKEND", DEFAULT_BACKEND).lower()

# Return appropriate config
if backend_name == "redis":
return dict(REDIS_CONFIG)
elif backend_name == "sqlite":
return dict(SQLITE_CONFIG)
elif backend_name == "postgresql":
return dict(POSTGRESQL_CONFIG)
elif backend_name == "dict":
return dict(DICT_CONFIG)
else:
raise ValueError(f"Unknown backend: {backend_name}")
Loading
Loading