Update Docker configuration, enhance error handling, and improve logging

- Added health check to the camera management API service in docker-compose.yml for better container reliability.
- Updated installation scripts in Dockerfile to check for existing dependencies before installation, improving efficiency.
- Enhanced error handling in the USDAVisionSystem class to allow partial operation if some components fail to start, preventing immediate shutdown.
- Improved logging throughout the application, including more detailed error messages and critical error handling in the main loop.
- Refactored WebSocketManager and CameraMonitor classes to use debug logging for connection events, reducing log noise.
This commit is contained in:
salirezav
2025-12-03 17:23:31 -05:00
parent 2bce817b4e
commit 933d4417a5
30 changed files with 4314 additions and 220 deletions

View File

@@ -15,7 +15,10 @@ CREATE TABLE IF NOT EXISTS public.experiments (
phase_id UUID NOT NULL REFERENCES public.experiment_phases(id) ON DELETE SET NULL,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
created_by UUID NOT NULL REFERENCES public.user_profiles(id)
created_by UUID NOT NULL REFERENCES public.user_profiles(id),
-- Ensure unique combination of experiment_number and phase_id
CONSTRAINT unique_experiment_number_phase UNIQUE (experiment_number, phase_id)
);
-- =============================================

View File

@@ -7,8 +7,7 @@
CREATE TABLE IF NOT EXISTS public.soaking (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
experiment_id UUID NOT NULL REFERENCES public.experiments(id) ON DELETE CASCADE,
repetition_id UUID REFERENCES public.experiment_repetitions(id) ON DELETE CASCADE,
repetition_id UUID NOT NULL REFERENCES public.experiment_repetitions(id) ON DELETE CASCADE,
scheduled_start_time TIMESTAMP WITH TIME ZONE NOT NULL,
actual_start_time TIMESTAMP WITH TIME ZONE,
soaking_duration_minutes INTEGER NOT NULL CHECK (soaking_duration_minutes > 0),
@@ -18,8 +17,7 @@ CREATE TABLE IF NOT EXISTS public.soaking (
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
created_by UUID NOT NULL REFERENCES public.user_profiles(id),
-- Ensure only one soaking per experiment or repetition
CONSTRAINT unique_soaking_per_experiment UNIQUE (experiment_id),
-- Ensure only one soaking per repetition
CONSTRAINT unique_soaking_per_repetition UNIQUE (repetition_id)
);
@@ -29,8 +27,7 @@ CREATE TABLE IF NOT EXISTS public.soaking (
CREATE TABLE IF NOT EXISTS public.airdrying (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
experiment_id UUID NOT NULL REFERENCES public.experiments(id) ON DELETE CASCADE,
repetition_id UUID REFERENCES public.experiment_repetitions(id) ON DELETE CASCADE,
repetition_id UUID NOT NULL REFERENCES public.experiment_repetitions(id) ON DELETE CASCADE,
scheduled_start_time TIMESTAMP WITH TIME ZONE NOT NULL,
actual_start_time TIMESTAMP WITH TIME ZONE,
duration_minutes INTEGER NOT NULL CHECK (duration_minutes > 0),
@@ -40,8 +37,7 @@ CREATE TABLE IF NOT EXISTS public.airdrying (
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
created_by UUID NOT NULL REFERENCES public.user_profiles(id),
-- Ensure only one airdrying per experiment or repetition
CONSTRAINT unique_airdrying_per_experiment UNIQUE (experiment_id),
-- Ensure only one airdrying per repetition
CONSTRAINT unique_airdrying_per_repetition UNIQUE (repetition_id)
);
@@ -51,8 +47,7 @@ CREATE TABLE IF NOT EXISTS public.airdrying (
CREATE TABLE IF NOT EXISTS public.cracking (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
experiment_id UUID NOT NULL REFERENCES public.experiments(id) ON DELETE CASCADE,
repetition_id UUID REFERENCES public.experiment_repetitions(id) ON DELETE CASCADE,
repetition_id UUID NOT NULL REFERENCES public.experiment_repetitions(id) ON DELETE CASCADE,
machine_type_id UUID NOT NULL REFERENCES public.machine_types(id),
scheduled_start_time TIMESTAMP WITH TIME ZONE NOT NULL,
actual_start_time TIMESTAMP WITH TIME ZONE,
@@ -61,8 +56,7 @@ CREATE TABLE IF NOT EXISTS public.cracking (
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
created_by UUID NOT NULL REFERENCES public.user_profiles(id),
-- Ensure only one cracking per experiment or repetition
CONSTRAINT unique_cracking_per_experiment UNIQUE (experiment_id),
-- Ensure only one cracking per repetition
CONSTRAINT unique_cracking_per_repetition UNIQUE (repetition_id)
);
@@ -72,8 +66,7 @@ CREATE TABLE IF NOT EXISTS public.cracking (
CREATE TABLE IF NOT EXISTS public.shelling (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
experiment_id UUID NOT NULL REFERENCES public.experiments(id) ON DELETE CASCADE,
repetition_id UUID REFERENCES public.experiment_repetitions(id) ON DELETE CASCADE,
repetition_id UUID NOT NULL REFERENCES public.experiment_repetitions(id) ON DELETE CASCADE,
scheduled_start_time TIMESTAMP WITH TIME ZONE NOT NULL,
actual_start_time TIMESTAMP WITH TIME ZONE,
actual_end_time TIMESTAMP WITH TIME ZONE,
@@ -81,8 +74,7 @@ CREATE TABLE IF NOT EXISTS public.shelling (
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
created_by UUID NOT NULL REFERENCES public.user_profiles(id),
-- Ensure only one shelling per experiment or repetition
CONSTRAINT unique_shelling_per_experiment UNIQUE (experiment_id),
-- Ensure only one shelling per repetition
CONSTRAINT unique_shelling_per_repetition UNIQUE (repetition_id)
);
@@ -90,12 +82,6 @@ CREATE TABLE IF NOT EXISTS public.shelling (
-- 5. INDEXES FOR PERFORMANCE
-- =============================================
-- Create indexes for experiment_id references
CREATE INDEX IF NOT EXISTS idx_soaking_experiment_id ON public.soaking(experiment_id);
CREATE INDEX IF NOT EXISTS idx_airdrying_experiment_id ON public.airdrying(experiment_id);
CREATE INDEX IF NOT EXISTS idx_cracking_experiment_id ON public.cracking(experiment_id);
CREATE INDEX IF NOT EXISTS idx_shelling_experiment_id ON public.shelling(experiment_id);
-- Create indexes for repetition references
CREATE INDEX IF NOT EXISTS idx_soaking_repetition_id ON public.soaking(repetition_id);
CREATE INDEX IF NOT EXISTS idx_airdrying_repetition_id ON public.airdrying(repetition_id);
@@ -138,11 +124,11 @@ CREATE OR REPLACE FUNCTION set_airdrying_scheduled_start_time()
RETURNS TRIGGER AS $$
BEGIN
-- If this is a new airdrying record and no scheduled_start_time is provided,
-- try to get it from the associated soaking's scheduled_end_time
-- try to get it from the associated soaking's scheduled_end_time for the same repetition
IF NEW.scheduled_start_time IS NULL THEN
SELECT s.scheduled_end_time INTO NEW.scheduled_start_time
FROM public.soaking s
WHERE s.experiment_id = NEW.experiment_id
WHERE s.repetition_id = NEW.repetition_id
LIMIT 1;
END IF;
RETURN NEW;
@@ -154,11 +140,11 @@ CREATE OR REPLACE FUNCTION set_cracking_scheduled_start_time()
RETURNS TRIGGER AS $$
BEGIN
-- If this is a new cracking record and no scheduled_start_time is provided,
-- try to get it from the associated airdrying's scheduled_end_time
-- try to get it from the associated airdrying's scheduled_end_time for the same repetition
IF NEW.scheduled_start_time IS NULL THEN
SELECT a.scheduled_end_time INTO NEW.scheduled_start_time
FROM public.airdrying a
WHERE a.experiment_id = NEW.experiment_id
WHERE a.repetition_id = NEW.repetition_id
LIMIT 1;
END IF;
RETURN NEW;

View File

@@ -6,6 +6,7 @@
-- =============================================
-- View for experiments with all phase information
-- Note: Since phases are now per-repetition, this view shows phase data from the first repetition
CREATE OR REPLACE VIEW public.experiments_with_phases AS
SELECT
e.id,
@@ -24,6 +25,8 @@ SELECT
ep.has_airdrying,
ep.has_cracking,
ep.has_shelling,
er.id as first_repetition_id,
er.repetition_number as first_repetition_number,
s.id as soaking_id,
s.scheduled_start_time as soaking_scheduled_start,
s.actual_start_time as soaking_actual_start,
@@ -47,11 +50,18 @@ SELECT
sh.actual_end_time as shelling_actual_end
FROM public.experiments e
LEFT JOIN public.experiment_phases ep ON e.phase_id = ep.id
LEFT JOIN public.soaking s ON s.experiment_id = e.id
LEFT JOIN public.airdrying ad ON ad.experiment_id = e.id
LEFT JOIN public.cracking c ON c.experiment_id = e.id
LEFT JOIN LATERAL (
SELECT id, repetition_number
FROM public.experiment_repetitions
WHERE experiment_id = e.id
ORDER BY repetition_number
LIMIT 1
) er ON true
LEFT JOIN public.soaking s ON s.repetition_id = er.id
LEFT JOIN public.airdrying ad ON ad.repetition_id = er.id
LEFT JOIN public.cracking c ON c.repetition_id = er.id
LEFT JOIN public.machine_types mt ON c.machine_type_id = mt.id
LEFT JOIN public.shelling sh ON sh.experiment_id = e.id;
LEFT JOIN public.shelling sh ON sh.repetition_id = er.id;
-- View for repetitions with phase information
CREATE OR REPLACE VIEW public.repetitions_with_phases AS

View File

@@ -0,0 +1,35 @@
-- Add repetition_id foreign key to cracker parameters tables
-- This migration adds a foreign key to link cracker parameters to their repetitions
-- =============================================
-- 1. ADD REPETITION_ID TO JC CRACKER PARAMETERS
-- =============================================
ALTER TABLE public.jc_cracker_parameters
ADD COLUMN IF NOT EXISTS repetition_id UUID REFERENCES public.experiment_repetitions(id) ON DELETE CASCADE;
-- Add index for performance
CREATE INDEX IF NOT EXISTS idx_jc_cracker_parameters_repetition_id
ON public.jc_cracker_parameters(repetition_id);
-- Add unique constraint to ensure one parameter set per repetition
ALTER TABLE public.jc_cracker_parameters
ADD CONSTRAINT unique_jc_cracker_parameters_per_repetition
UNIQUE (repetition_id);
-- =============================================
-- 2. ADD REPETITION_ID TO MEYER CRACKER PARAMETERS
-- =============================================
ALTER TABLE public.meyer_cracker_parameters
ADD COLUMN IF NOT EXISTS repetition_id UUID REFERENCES public.experiment_repetitions(id) ON DELETE CASCADE;
-- Add index for performance
CREATE INDEX IF NOT EXISTS idx_meyer_cracker_parameters_repetition_id
ON public.meyer_cracker_parameters(repetition_id);
-- Add unique constraint to ensure one parameter set per repetition
ALTER TABLE public.meyer_cracker_parameters
ADD CONSTRAINT unique_meyer_cracker_parameters_per_repetition
UNIQUE (repetition_id);