- error handling now uses a more comprehensive error communication system.

This commit is contained in:
Josako
2025-09-11 14:46:28 +02:00
parent 7cb19ca21e
commit a325fa5084
13 changed files with 216 additions and 59 deletions

View File

@@ -0,0 +1,22 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Unauthorized</title>
<style>
body { font-family: system-ui, -apple-system, Segoe UI, Roboto, Helvetica, Arial, sans-serif; background:#f7f7f9; color:#222; }
.wrap { max-width: 720px; margin: 10vh auto; background:#fff; border:1px solid #e5e7eb; border-radius:12px; padding:32px; box-shadow: 0 8px 24px rgba(0,0,0,0.06); }
h1 { margin: 0 0 8px; font-size: 28px; }
p { margin: 0 0 16px; line-height:1.6; }
a.btn { display:inline-block; padding:10px 16px; background:#2c3e50; color:#fff; text-decoration:none; border-radius:8px; }
</style>
</head>
<body>
<main class="wrap">
<h1>Not authorized</h1>
<p>Your session may have expired or this action is not permitted.</p>
<p><a class="btn" href="/">Go to home</a></p>
</main>
</body>
</html>

View File

@@ -0,0 +1,22 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Forbidden</title>
<style>
body { font-family: system-ui, -apple-system, Segoe UI, Roboto, Helvetica, Arial, sans-serif; background:#f7f7f9; color:#222; }
.wrap { max-width: 720px; margin: 10vh auto; background:#fff; border:1px solid #e5e7eb; border-radius:12px; padding:32px; box-shadow: 0 8px 24px rgba(0,0,0,0.06); }
h1 { margin: 0 0 8px; font-size: 28px; }
p { margin: 0 0 16px; line-height:1.6; }
a.btn { display:inline-block; padding:10px 16px; background:#2c3e50; color:#fff; text-decoration:none; border-radius:8px; }
</style>
</head>
<body>
<main class="wrap">
<h1>Access forbidden</h1>
<p>You don't have permission to access this resource.</p>
<p><a class="btn" href="/">Go to home</a></p>
</main>
</body>
</html>

View File

@@ -0,0 +1,22 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Page not found</title>
<style>
body { font-family: system-ui, -apple-system, Segoe UI, Roboto, Helvetica, Arial, sans-serif; background:#f7f7f9; color:#222; }
.wrap { max-width: 720px; margin: 10vh auto; background:#fff; border:1px solid #e5e7eb; border-radius:12px; padding:32px; box-shadow: 0 8px 24px rgba(0,0,0,0.06); }
h1 { margin: 0 0 8px; font-size: 28px; }
p { margin: 0 0 16px; line-height:1.6; }
a.btn { display:inline-block; padding:10px 16px; background:#2c3e50; color:#fff; text-decoration:none; border-radius:8px; }
</style>
</head>
<body>
<main class="wrap">
<h1>Page not found</h1>
<p>The page you are looking for doesnt exist or has been moved.</p>
<p><a class="btn" href="/">Go to home</a></p>
</main>
</body>
</html>

View File

@@ -0,0 +1,22 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Something went wrong</title>
<style>
body { font-family: system-ui, -apple-system, Segoe UI, Roboto, Helvetica, Arial, sans-serif; background:#f7f7f9; color:#222; }
.wrap { max-width: 720px; margin: 10vh auto; background:#fff; border:1px solid #e5e7eb; border-radius:12px; padding:32px; box-shadow: 0 8px 24px rgba(0,0,0,0.06); }
h1 { margin: 0 0 8px; font-size: 28px; }
p { margin: 0 0 16px; line-height:1.6; }
a.btn { display:inline-block; padding:10px 16px; background:#2c3e50; color:#fff; text-decoration:none; border-radius:8px; }
</style>
</head>
<body>
<main class="wrap">
<h1>Were sorry — something went wrong</h1>
<p>Please try again later. If the issue persists, contact support.</p>
<p><a class="btn" href="/">Go to home</a></p>
</main>
</body>
</html>

View File

@@ -0,0 +1,22 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Error</title>
<style>
body { font-family: system-ui, -apple-system, Segoe UI, Roboto, Helvetica, Arial, sans-serif; background:#f7f7f9; color:#222; }
.wrap { max-width: 720px; margin: 10vh auto; background:#fff; border:1px solid #e5e7eb; border-radius:12px; padding:32px; box-shadow: 0 8px 24px rgba(0,0,0,0.06); }
h1 { margin: 0 0 8px; font-size: 28px; }
p { margin: 0 0 16px; line-height:1.6; }
a.btn { display:inline-block; padding:10px 16px; background:#2c3e50; color:#fff; text-decoration:none; border-radius:8px; }
</style>
</head>
<body>
<main class="wrap">
<h1>Oops! Something went wrong</h1>
<p>Please try again. If the issue persists, contact support.</p>
<p><a class="btn" href="/">Go to home</a></p>
</main>
</body>
</html>

View File

@@ -10,41 +10,54 @@ from common.utils.nginx_utils import prefixed_url_for
def not_found_error(error): def not_found_error(error):
if not current_user.is_authenticated: profile = current_app.config.get('ERRORS_PROFILE', 'web_app')
return redirect(prefixed_url_for('security.login')) if profile == 'web_app':
if not current_user.is_authenticated:
return redirect(prefixed_url_for('security.login', for_redirect=True))
current_app.logger.error(f"Not Found Error: {error}") current_app.logger.error(f"Not Found Error: {error}")
current_app.logger.error(traceback.format_exc()) current_app.logger.error(traceback.format_exc())
return render_template('error/404.html'), 404 return render_template('error/404.html'), 404
def internal_server_error(error): def internal_server_error(error):
if not current_user.is_authenticated: profile = current_app.config.get('ERRORS_PROFILE', 'web_app')
return redirect(prefixed_url_for('security.login')) if profile == 'web_app':
if not current_user.is_authenticated:
return redirect(prefixed_url_for('security.login', for_redirect=True))
current_app.logger.error(f"Internal Server Error: {error}") current_app.logger.error(f"Internal Server Error: {error}")
current_app.logger.error(traceback.format_exc()) current_app.logger.error(traceback.format_exc())
return render_template('error/500.html'), 500 return render_template('error/500.html'), 500
def not_authorised_error(error): def not_authorised_error(error):
if not current_user.is_authenticated: profile = current_app.config.get('ERRORS_PROFILE', 'web_app')
return redirect(prefixed_url_for('security.login')) if profile == 'web_app':
if not current_user.is_authenticated:
return redirect(prefixed_url_for('security.login', for_redirect=True))
current_app.logger.error(f"Not Authorised Error: {error}") current_app.logger.error(f"Not Authorised Error: {error}")
current_app.logger.error(traceback.format_exc()) current_app.logger.error(traceback.format_exc())
return render_template('error/401.html') return render_template('error/401.html'), 401
def access_forbidden(error): def access_forbidden(error):
if not current_user.is_authenticated: profile = current_app.config.get('ERRORS_PROFILE', 'web_app')
return redirect(prefixed_url_for('security.login')) if profile == 'web_app':
if not current_user.is_authenticated:
return redirect(prefixed_url_for('security.login', for_redirect=True))
current_app.logger.error(f"Access Forbidden: {error}") current_app.logger.error(f"Access Forbidden: {error}")
current_app.logger.error(traceback.format_exc()) current_app.logger.error(traceback.format_exc())
return render_template('error/403.html') return render_template('error/403.html'), 403
def key_error_handler(error): def key_error_handler(error):
profile = current_app.config.get('ERRORS_PROFILE', 'web_app')
# Check if the KeyError is specifically for 'tenant' # Check if the KeyError is specifically for 'tenant'
if str(error) == "'tenant'": if str(error) == "'tenant'":
return redirect(prefixed_url_for('security.login')) if profile == 'web_app':
return redirect(prefixed_url_for('security.login', for_redirect=True))
else:
current_app.logger.warning("Session tenant missing in chat_client context")
return render_template('error/401.html'), 401
# For other KeyErrors, you might want to log the error and return a generic error page # For other KeyErrors, you might want to log the error and return a generic error page
current_app.logger.error(f"Key Error: {error}") current_app.logger.error(f"Key Error: {error}")
current_app.logger.error(traceback.format_exc()) current_app.logger.error(traceback.format_exc())
@@ -79,19 +92,24 @@ def no_tenant_selected_error(error):
"""Handle errors when no tenant is selected in the current session. """Handle errors when no tenant is selected in the current session.
This typically happens when a session expires or becomes invalid after This typically happens when a session expires or becomes invalid after
a long period of inactivity. The user will be redirected to the login page. a long period of inactivity. The user will be redirected to the login page (web_app)
or shown an error page (chat_client).
""" """
profile = current_app.config.get('ERRORS_PROFILE', 'web_app')
current_app.logger.error(f"No Session Tenant Error: {error}") current_app.logger.error(f"No Session Tenant Error: {error}")
current_app.logger.error(traceback.format_exc()) current_app.logger.error(traceback.format_exc())
flash('Your session expired. You will have to re-enter your credentials', 'warning') flash('Your session expired. You will have to re-enter your credentials', 'warning')
# Perform logout if user is authenticated if profile == 'web_app':
if current_user.is_authenticated: # Perform logout if user is authenticated
from flask_security.utils import logout_user if current_user.is_authenticated:
logout_user() from flask_security.utils import logout_user
logout_user()
# Redirect to login page # Redirect to login page
return redirect(prefixed_url_for('security.login')) return redirect(prefixed_url_for('security.login', for_redirect=True))
else:
# chat_client: render 401 page
return render_template('error/401.html'), 401
def general_exception(e): def general_exception(e):
@@ -122,7 +140,10 @@ def template_syntax_error(error):
error_details=f"Error in template '{error.filename}' at line {error.lineno}: {error.message}"), 500 error_details=f"Error in template '{error.filename}' at line {error.lineno}: {error.message}"), 500
def register_error_handlers(app): def register_error_handlers(app, profile: str = 'web_app'):
# Store profile in app config to drive handler behavior
app.config['ERRORS_PROFILE'] = profile
app.register_error_handler(404, not_found_error) app.register_error_handler(404, not_found_error)
app.register_error_handler(500, internal_server_error) app.register_error_handler(500, internal_server_error)
app.register_error_handler(401, not_authorised_error) app.register_error_handler(401, not_authorised_error)

View File

@@ -363,8 +363,6 @@ class DevConfig(Config):
EXPLAIN_TEMPLATE_LOADING = False EXPLAIN_TEMPLATE_LOADING = False
# Define the nginx prefix used for the specific apps # Define the nginx prefix used for the specific apps
EVEAI_APP_LOCATION_PREFIX = ''
EVEAI_CHAT_LOCATION_PREFIX = '/chat'
CHAT_CLIENT_PREFIX = 'chat-client/chat/' CHAT_CLIENT_PREFIX = 'chat-client/chat/'
# Define the static path # Define the static path
@@ -391,8 +389,6 @@ class TestConfig(Config):
EXPLAIN_TEMPLATE_LOADING = False EXPLAIN_TEMPLATE_LOADING = False
# Define the nginx prefix used for the specific apps # Define the nginx prefix used for the specific apps
EVEAI_APP_LOCATION_PREFIX = ''
EVEAI_CHAT_LOCATION_PREFIX = '/chat'
CHAT_CLIENT_PREFIX = 'chat-client/chat/' CHAT_CLIENT_PREFIX = 'chat-client/chat/'
# Define the static path # Define the static path
@@ -419,9 +415,7 @@ class StagingConfig(Config):
EXPLAIN_TEMPLATE_LOADING = False EXPLAIN_TEMPLATE_LOADING = False
# Define the nginx prefix used for the specific apps # Define the nginx prefix used for the specific apps
EVEAI_APP_LOCATION_PREFIX = '' CHAT_CLIENT_PREFIX = 'chat-client/chat/'
EVEAI_CHAT_LOCATION_PREFIX = ''
CHAT_CLIENT_PREFIX = ''
# Define the static path # Define the static path
STATIC_URL = 'https://evie-staging-static.askeveai.com' STATIC_URL = 'https://evie-staging-static.askeveai.com'
@@ -452,11 +446,10 @@ class ProdConfig(Config):
WTF_CSRF_SSL_STRICT = True # Set to True if using HTTPS WTF_CSRF_SSL_STRICT = True # Set to True if using HTTPS
# Define the nginx prefix used for the specific apps # Define the nginx prefix used for the specific apps
EVEAI_APP_LOCATION_PREFIX = '' EVEAI_CHAT_LOCATION_PREFIX = 'EVEAI_APP_LOCATION_PREFIX'
EVEAI_CHAT_LOCATION_PREFIX = ''
# Define the static path # Define the static path
STATIC_URL = 'https://evie-staging-static.askeveai.com' STATIC_URL = 'https://evie-prod-static.askeveai.com'
# PATH settings # PATH settings
ffmpeg_path = '/usr/bin/ffmpeg' ffmpeg_path = '/usr/bin/ffmpeg'

View File

@@ -1,18 +1,20 @@
import logging import logging
import os import os
from flask import Flask, jsonify, request, url_for from flask import Flask, jsonify, request, url_for, session as flask_session
from werkzeug.middleware.proxy_fix import ProxyFix from werkzeug.middleware.proxy_fix import ProxyFix
import logging.config import logging.config
from jinja2 import ChoiceLoader, FileSystemLoader
from common.extensions import (db, bootstrap, cors, csrf, session, from common.extensions import (db, bootstrap, cors, csrf, session,
minio_client, simple_encryption, metrics, cache_manager, content_manager) minio_client, simple_encryption, metrics, cache_manager, content_manager)
from common.models.user import Tenant, SpecialistMagicLinkTenant from common.models.user import Tenant, SpecialistMagicLinkTenant
from config.logging_config import configure_logging from config.logging_config import configure_logging
from eveai_chat_client.utils.errors import register_error_handlers from common.utils.errors import register_error_handlers
from common.utils.celery_utils import make_celery, init_celery from common.utils.celery_utils import make_celery, init_celery
from common.utils.template_filters import register_filters from common.utils.template_filters import register_filters
from config.config import get_config from config.config import get_config
from common.utils.chat_utils import get_default_chat_customisation
def create_app(config_file=None): def create_app(config_file=None):
@@ -57,11 +59,23 @@ def create_app(config_file=None):
app.celery = make_celery(app.name, app.config) app.celery = make_celery(app.name, app.config)
init_celery(app.celery, app) init_celery(app.celery, app)
# Configure template loader with fallback to common/templates
try:
import os as _os
common_templates_path = _os.path.normpath(_os.path.join(app.root_path, '..', 'common', 'templates'))
app.jinja_loader = ChoiceLoader([
app.jinja_loader,
FileSystemLoader(common_templates_path),
])
app.logger.debug(f"Added common templates path: {common_templates_path}")
except Exception as e:
app.logger.error(f"Failed to configure ChoiceLoader for common templates: {e}")
# Register Blueprints # Register Blueprints
register_blueprints(app) register_blueprints(app)
# Register Error Handlers # Register Error Handlers (shared, profile-aware)
register_error_handlers(app) register_error_handlers(app, profile='chat_client')
# Register Cache Handlers # Register Cache Handlers
register_cache_handlers(app) register_cache_handlers(app)
@@ -85,6 +99,19 @@ def create_app(config_file=None):
# Register template filters # Register template filters
register_filters(app) register_filters(app)
# Always inject chat customisation for templates (safe defaults)
@app.context_processor
def inject_customisation():
try:
tm = flask_session.get('tenant_make')
options = None
if tm and isinstance(tm, dict):
options = tm.get('chat_customisation_options')
customisation = get_default_chat_customisation(options)
except Exception:
customisation = get_default_chat_customisation(None)
return {'customisation': customisation}
app.logger.info(f"EveAI Chat Client Started Successfully (PID: {os.getpid()})") app.logger.info(f"EveAI Chat Client Started Successfully (PID: {os.getpid()})")
app.logger.info("-------------------------------------------------------------------------------------------------") app.logger.info("-------------------------------------------------------------------------------------------------")
@@ -115,8 +142,7 @@ def register_extensions(app):
def register_blueprints(app): def register_blueprints(app):
from .views.chat_views import chat_bp from .views.chat_views import chat_bp
app.register_blueprint(chat_bp) app.register_blueprint(chat_bp)
from .views.error_views import error_bp # Do not register local error blueprint; use shared error handlers from common
app.register_blueprint(error_bp)
from .views.healthz_views import healthz_bp from .views.healthz_views import healthz_bp
app.register_blueprint(healthz_bp) app.register_blueprint(healthz_bp)

View File

@@ -9,31 +9,31 @@ from common.utils.eveai_exceptions import EveAINoSessionTenant
def not_found_error(error): def not_found_error(error):
current_app.logger.error(f"Not Found Error: {error}") current_app.logger.error(f"Not Found Error: {error}")
current_app.logger.error(traceback.format_exc()) current_app.logger.error(traceback.format_exc())
return render_template('error.html', message="Page not found."), 404 return render_template('error/404.html'), 404
def internal_server_error(error): def internal_server_error(error):
current_app.logger.error(f"Internal Server Error: {error}") current_app.logger.error(f"Internal Server Error: {error}")
current_app.logger.error(traceback.format_exc()) current_app.logger.error(traceback.format_exc())
return render_template('error.html', message="Internal server error."), 500 return render_template('error/500.html'), 500
def not_authorised_error(error): def not_authorised_error(error):
current_app.logger.error(f"Not Authorised Error: {error}") current_app.logger.error(f"Not Authorised Error: {error}")
current_app.logger.error(traceback.format_exc()) current_app.logger.error(traceback.format_exc())
return render_template('error.html', message="Not authorized."), 401 return render_template('error/401.html'), 401
def access_forbidden(error): def access_forbidden(error):
current_app.logger.error(f"Access Forbidden: {error}") current_app.logger.error(f"Access Forbidden: {error}")
current_app.logger.error(traceback.format_exc()) current_app.logger.error(traceback.format_exc())
return render_template('error.html', message="Access forbidden."), 403 return render_template('error/403.html'), 403
def key_error_handler(error): def key_error_handler(error):
current_app.logger.error(f"Key Error: {error}") current_app.logger.error(f"Key Error: {error}")
current_app.logger.error(traceback.format_exc()) current_app.logger.error(traceback.format_exc())
return render_template('error.html', message="An unexpected error occurred."), 500 return render_template('error/500.html'), 500
def attribute_error_handler(error): def attribute_error_handler(error):
@@ -41,7 +41,7 @@ def attribute_error_handler(error):
error_msg = str(error) error_msg = str(error)
current_app.logger.error(f"AttributeError: {error_msg}") current_app.logger.error(f"AttributeError: {error_msg}")
current_app.logger.error(traceback.format_exc()) current_app.logger.error(traceback.format_exc())
return render_template('error.html', message="An application error occurred."), 500 return render_template('error/500.html'), 500
def no_tenant_selected_error(error): def no_tenant_selected_error(error):

View File

@@ -37,9 +37,7 @@ def log_after_request(response):
@chat_bp.route('/') @chat_bp.route('/')
def index(): def index():
customisation = get_default_chat_customisation() return render_template('error/404.html'), 404
return render_template('error.html', message="Please use a valid magic link to access the chat.",
customisation=customisation)
@chat_bp.route('/<magic_link_code>') @chat_bp.route('/<magic_link_code>')
@@ -53,14 +51,14 @@ def chat(magic_link_code):
if not magic_link_tenant: if not magic_link_tenant:
current_app.logger.error(f"Invalid magic link code: {magic_link_code}") current_app.logger.error(f"Invalid magic link code: {magic_link_code}")
return render_template('error.html', message="Invalid magic link code.") return render_template('error/404.html'), 404
# Get tenant information # Get tenant information
tenant_id = magic_link_tenant.tenant_id tenant_id = magic_link_tenant.tenant_id
tenant = Tenant.query.get(tenant_id) tenant = Tenant.query.get(tenant_id)
if not tenant: if not tenant:
current_app.logger.error(f"Tenant not found for ID: {tenant_id}") current_app.logger.error(f"Tenant not found for ID: {tenant_id}")
return render_template('error.html', message="Tenant not found.") return render_template('error/404.html'), 404
# Switch to tenant schema # Switch to tenant schema
Database(tenant_id).switch_schema() Database(tenant_id).switch_schema()
@@ -68,19 +66,19 @@ def chat(magic_link_code):
specialist_ml = SpecialistMagicLink.query.filter_by(magic_link_code=magic_link_code).first() specialist_ml = SpecialistMagicLink.query.filter_by(magic_link_code=magic_link_code).first()
if not specialist_ml: if not specialist_ml:
current_app.logger.error(f"Specialist magic link not found in tenant schema: {tenant_id}") current_app.logger.error(f"Specialist magic link not found in tenant schema: {tenant_id}")
return render_template('error.html', message="Specialist configuration not found.") return render_template('error/404.html'), 404
# Get relevant TenantMake # Get relevant TenantMake
tenant_make = TenantMake.query.get(specialist_ml.tenant_make_id) tenant_make = TenantMake.query.get(specialist_ml.tenant_make_id)
if not tenant_make: if not tenant_make:
current_app.logger.error(f"Tenant make not found: {specialist_ml.tenant_make_id}") current_app.logger.error(f"Tenant make not found: {specialist_ml.tenant_make_id}")
return render_template('error.html', message="Tenant make not found.") return render_template('error/500.html'), 500
# Get specialist details # Get specialist details
specialist = Specialist.query.get(specialist_ml.specialist_id) specialist = Specialist.query.get(specialist_ml.specialist_id)
if not specialist: if not specialist:
current_app.logger.error(f"Specialist not found: {specialist_ml.specialist_id}") current_app.logger.error(f"Specialist not found: {specialist_ml.specialist_id}")
return render_template('error.html', message="Specialist not found.") return render_template('error/404.html'), 404
# Store necessary information in session # Store necessary information in session
session['tenant'] = tenant.to_dict() session['tenant'] = tenant.to_dict()
@@ -124,7 +122,7 @@ def chat(magic_link_code):
except Exception as e: except Exception as e:
current_app.logger.error(f"Error in chat view: {str(e)}", exc_info=True) current_app.logger.error(f"Error in chat view: {str(e)}", exc_info=True)
return render_template('error.html', message="An error occurred while setting up the chat.") return render_template('error/500.html'), 500
@chat_bp.route('/api/send_message', methods=['POST']) @chat_bp.route('/api/send_message', methods=['POST'])

View File

@@ -28,18 +28,19 @@ def create_app(config_file=None):
configure_logging() configure_logging()
app.logger.info('Starting up eveai_chat_workers...')
register_extensions(app) register_extensions(app)
register_cache_handlers(app)
from . import specialists, retrievers from . import specialists, retrievers
celery = make_celery(app.name, app.config) celery = make_celery(app.name, app.config)
init_celery(celery, app) init_celery(celery, app)
register_cache_handlers(app) from . import tasks
from eveai_chat_workers import tasks app.logger.info("EveAI Worker Server Started Successfully")
print(tasks.tasks_ping()) app.logger.info("-------------------------------------------------------------------------------------------------")
return app, celery return app, celery

View File

@@ -5,6 +5,7 @@ import traceback
from flask import current_app from flask import current_app
from celery import states from celery import states
from sqlalchemy.exc import SQLAlchemyError, InterfaceError, OperationalError from sqlalchemy.exc import SQLAlchemyError, InterfaceError, OperationalError
from redis.exceptions import ConnectionError as RedisConnectionError, TimeoutError as RedisTimeoutError
from common.utils.config_field_types import TaggingFields from common.utils.config_field_types import TaggingFields
from common.utils.database import Database from common.utils.database import Database
@@ -21,7 +22,9 @@ from common.utils.execution_progress import ExecutionProgressTracker
# Healthcheck task # Healthcheck task
@current_celery.task(name='ping', queue='llm_interactions') @current_celery.task(bind=True, name='ping', queue='llm_interactions',
autoretry_for=(InterfaceError, OperationalError, RedisConnectionError, RedisTimeoutError, OSError),
retry_backoff=True, retry_jitter=True, max_retries=5)
def ping(): def ping():
return 'pong' return 'pong'
@@ -215,7 +218,9 @@ def prepare_arguments(specialist: Any, arguments: Dict[str, Any]) -> Dict[str, A
raise ArgumentPreparationError(str(e)) raise ArgumentPreparationError(str(e))
@current_celery.task(bind=True, name='execute_specialist', queue='llm_interactions', autoretry_for=(InterfaceError, OperationalError), retry_backoff=True, retry_jitter=True, max_retries=5) @current_celery.task(bind=True, name='execute_specialist', queue='llm_interactions',
autoretry_for=(InterfaceError, OperationalError),
retry_backoff=True, retry_jitter=True, max_retries=5)
def execute_specialist(self, tenant_id: int, specialist_id: int, arguments: Dict[str, Any], def execute_specialist(self, tenant_id: int, specialist_id: int, arguments: Dict[str, Any],
session_id: str, user_timezone: str) -> dict: session_id: str, user_timezone: str) -> dict:
""" """

View File

@@ -11,6 +11,7 @@ from langchain_core.prompts import ChatPromptTemplate
from langchain_core.runnables import RunnablePassthrough from langchain_core.runnables import RunnablePassthrough
from sqlalchemy import or_ from sqlalchemy import or_
from sqlalchemy.exc import SQLAlchemyError, InterfaceError, OperationalError from sqlalchemy.exc import SQLAlchemyError, InterfaceError, OperationalError
from redis.exceptions import ConnectionError as RedisConnectionError, TimeoutError as RedisTimeoutError
import traceback import traceback
from common.extensions import db, cache_manager from common.extensions import db, cache_manager
@@ -32,13 +33,15 @@ from common.utils.config_field_types import json_to_pattern_list
# Healthcheck task # Healthcheck task
@current_celery.task(name='ping', queue='embeddings') @current_celery.task(bind=True, name='ping', queue='embeddings',
autoretry_for=(InterfaceError, OperationalError, RedisConnectionError, RedisTimeoutError, OSError),
retry_backoff=True, retry_jitter=True, max_retries=5)
def ping(): def ping():
return 'pong' return 'pong'
@current_celery.task(bind=True, name='create_embeddings', queue='embeddings', @current_celery.task(bind=True, name='create_embeddings', queue='embeddings',
autoretry_for=(InterfaceError, OperationalError), autoretry_for=(InterfaceError, OperationalError, RedisConnectionError, RedisTimeoutError, OSError),
retry_backoff=True, retry_jitter=True, max_retries=5) retry_backoff=True, retry_jitter=True, max_retries=5)
def create_embeddings(self, tenant_id, document_version_id): def create_embeddings(self, tenant_id, document_version_id):
document_version = None document_version = None