Add index and classifier status

This commit is contained in:
shamoon 2024-02-13 19:28:48 -08:00
parent d651e3132f
commit d56eb2eed5
11 changed files with 211 additions and 82 deletions

View File

@ -1540,7 +1540,7 @@
<source>Error retrieving users</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/admin/settings/settings.component.ts</context>
<context context-type="linenumber">182</context>
<context context-type="linenumber">185</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/admin/users-groups/users-groups.component.ts</context>
@ -1551,7 +1551,7 @@
<source>Error retrieving groups</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/admin/settings/settings.component.ts</context>
<context context-type="linenumber">201</context>
<context context-type="linenumber">204</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/admin/users-groups/users-groups.component.ts</context>
@ -1562,35 +1562,35 @@
<source>Saved view &quot;<x id="PH" equiv-text="savedView.name"/>&quot; deleted.</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/admin/settings/settings.component.ts</context>
<context context-type="linenumber">414</context>
<context context-type="linenumber">417</context>
</context-group>
</trans-unit>
<trans-unit id="7217000812750597833" datatype="html">
<source>Settings were saved successfully.</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/admin/settings/settings.component.ts</context>
<context context-type="linenumber">540</context>
<context context-type="linenumber">543</context>
</context-group>
</trans-unit>
<trans-unit id="525012668859298131" datatype="html">
<source>Settings were saved successfully. Reload is required to apply some changes.</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/admin/settings/settings.component.ts</context>
<context context-type="linenumber">544</context>
<context context-type="linenumber">547</context>
</context-group>
</trans-unit>
<trans-unit id="8491974984518503778" datatype="html">
<source>Reload now</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/admin/settings/settings.component.ts</context>
<context context-type="linenumber">545</context>
<context context-type="linenumber">548</context>
</context-group>
</trans-unit>
<trans-unit id="3011185103048412841" datatype="html">
<source>An error occurred while saving settings.</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/admin/settings/settings.component.ts</context>
<context context-type="linenumber">555</context>
<context context-type="linenumber">558</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/app-frame/app-frame.component.ts</context>
@ -1601,7 +1601,7 @@
<source>Error while storing settings on server.</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/admin/settings/settings.component.ts</context>
<context context-type="linenumber">589</context>
<context context-type="linenumber">592</context>
</context-group>
</trans-unit>
<trans-unit id="2991443309752293110" datatype="html">
@ -4160,7 +4160,7 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/system-status-dialog/system-status-dialog.component.html</context>
<context context-type="linenumber">124</context>
<context context-type="linenumber">144</context>
</context-group>
</trans-unit>
<trans-unit id="595732867213154214" datatype="html">
@ -4449,18 +4449,11 @@
<context context-type="linenumber">41</context>
</context-group>
</trans-unit>
<trans-unit id="2375260419993138758" datatype="html">
<source>URL</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/system-status-dialog/system-status-dialog.component.html</context>
<context context-type="linenumber">47</context>
</context-group>
</trans-unit>
<trans-unit id="5611592591303869712" datatype="html">
<source>Status</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/system-status-dialog/system-status-dialog.component.html</context>
<context context-type="linenumber">49</context>
<context context-type="linenumber">47</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/toasts/toasts.component.html</context>
@ -4475,49 +4468,67 @@
<source>Migration Status</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/system-status-dialog/system-status-dialog.component.html</context>
<context context-type="linenumber">58</context>
<context context-type="linenumber">56</context>
</context-group>
</trans-unit>
<trans-unit id="7881311375431899727" datatype="html">
<source>Latest Migration</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/system-status-dialog/system-status-dialog.component.html</context>
<context context-type="linenumber">66</context>
<context context-type="linenumber">64</context>
</context-group>
</trans-unit>
<trans-unit id="4632965004151576238" datatype="html">
<source>Pending Migrations</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/system-status-dialog/system-status-dialog.component.html</context>
<context context-type="linenumber">68</context>
<context context-type="linenumber">66</context>
</context-group>
</trans-unit>
<trans-unit id="6904866445262015585" datatype="html">
<source>Tasks</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/system-status-dialog/system-status-dialog.component.html</context>
<context context-type="linenumber">85</context>
</context-group>
</trans-unit>
<trans-unit id="1044837289640087179" datatype="html">
<source>Redis URL</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/system-status-dialog/system-status-dialog.component.html</context>
<context context-type="linenumber">89</context>
<context context-type="linenumber">83</context>
</context-group>
</trans-unit>
<trans-unit id="6911698235105017958" datatype="html">
<source>Redis Status</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/system-status-dialog/system-status-dialog.component.html</context>
<context context-type="linenumber">91</context>
<context context-type="linenumber">87</context>
</context-group>
</trans-unit>
<trans-unit id="5349496739889768589" datatype="html">
<source>Celery Status</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/system-status-dialog/system-status-dialog.component.html</context>
<context context-type="linenumber">100</context>
<context context-type="linenumber">96</context>
</context-group>
</trans-unit>
<trans-unit id="1086740373716043695" datatype="html">
<source>Index Status</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/system-status-dialog/system-status-dialog.component.html</context>
<context context-type="linenumber">105</context>
</context-group>
</trans-unit>
<trans-unit id="4089509911694721896" datatype="html">
<source>Last Updated</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/system-status-dialog/system-status-dialog.component.html</context>
<context context-type="linenumber">115</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/system-status-dialog/system-status-dialog.component.html</context>
<context context-type="linenumber">127</context>
</context-group>
</trans-unit>
<trans-unit id="5232507269140097134" datatype="html">
<source>Classifier Status</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/system-status-dialog/system-status-dialog.component.html</context>
<context context-type="linenumber">117</context>
</context-group>
</trans-unit>
<trans-unit id="6732151329960766506" datatype="html">

View File

@ -44,9 +44,9 @@ import { ConfirmButtonComponent } from '../../common/confirm-button/confirm-butt
import { SystemStatusDialogComponent } from '../../common/system-status-dialog/system-status-dialog.component'
import { SystemStatusService } from 'src/app/services/system-status.service'
import {
PaperlessSystemStatus,
PaperlessInstallType,
PaperlessConnectionStatus,
SystemStatus,
InstallType,
SystemStatusItemStatus,
} from 'src/app/data/system-status'
const savedViews = [
@ -388,15 +388,15 @@ describe('SettingsComponent', () => {
})
it('should load system status on initialize, show errors if needed', () => {
const status: PaperlessSystemStatus = {
const status: SystemStatus = {
pngx_version: '2.4.3',
server_os: 'macOS-14.1.1-arm64-arm-64bit',
install_type: PaperlessInstallType.BareMetal,
install_type: InstallType.BareMetal,
storage: { total: 494384795648, available: 13573525504 },
database: {
type: 'sqlite',
url: '/paperless-ngx/data/db.sqlite3',
status: PaperlessConnectionStatus.ERROR,
status: SystemStatusItemStatus.ERROR,
error: null,
migration_status: {
latest_migration: 'socialaccount.0006_alter_socialaccount_extra_data',
@ -405,10 +405,16 @@ describe('SettingsComponent', () => {
},
tasks: {
redis_url: 'redis://localhost:6379',
redis_status: PaperlessConnectionStatus.ERROR,
redis_status: SystemStatusItemStatus.ERROR,
redis_error:
'Error 61 connecting to localhost:6379. Connection refused.',
celery_status: PaperlessConnectionStatus.ERROR,
celery_status: SystemStatusItemStatus.ERROR,
index_status: SystemStatusItemStatus.OK,
index_last_modified: new Date(),
index_error: null,
classifier_status: SystemStatusItemStatus.OK,
classifier_last_modified: new Date(),
classifier_error: null,
},
}
jest.spyOn(systemStatusService, 'get').mockReturnValue(of(status))
@ -416,9 +422,9 @@ describe('SettingsComponent', () => {
expect(component['systemStatus']).toEqual(status) // private
expect(component.systemStatusHasErrors).toBeTruthy()
// coverage
component['systemStatus'].database.status = PaperlessConnectionStatus.OK
component['systemStatus'].tasks.redis_status = PaperlessConnectionStatus.OK
component['systemStatus'].tasks.celery_status = PaperlessConnectionStatus.OK
component['systemStatus'].database.status = SystemStatusItemStatus.OK
component['systemStatus'].tasks.redis_status = SystemStatusItemStatus.OK
component['systemStatus'].tasks.celery_status = SystemStatusItemStatus.OK
expect(component.systemStatusHasErrors).toBeFalsy()
})

View File

@ -47,8 +47,8 @@ import { ComponentWithPermissions } from '../../with-permissions/with-permission
import { SystemStatusDialogComponent } from '../../common/system-status-dialog/system-status-dialog.component'
import { SystemStatusService } from 'src/app/services/system-status.service'
import {
PaperlessConnectionStatus,
PaperlessSystemStatus,
SystemStatusItemStatus,
SystemStatus,
} from 'src/app/data/system-status'
enum SettingsNavIDs {
@ -121,14 +121,15 @@ export class SettingsComponent
users: User[]
groups: Group[]
private systemStatus: PaperlessSystemStatus
private systemStatus: SystemStatus
get systemStatusHasErrors(): boolean {
return (
this.systemStatus.database.status === PaperlessConnectionStatus.ERROR ||
this.systemStatus.tasks.redis_status ===
PaperlessConnectionStatus.ERROR ||
this.systemStatus.tasks.celery_status === PaperlessConnectionStatus.ERROR
this.systemStatus.database.status === SystemStatusItemStatus.ERROR ||
this.systemStatus.tasks.redis_status === SystemStatusItemStatus.ERROR ||
this.systemStatus.tasks.celery_status === SystemStatusItemStatus.ERROR ||
this.systemStatus.tasks.index_status === SystemStatusItemStatus.ERROR ||
this.systemStatus.tasks.classifier_status === SystemStatusItemStatus.ERROR
)
}

View File

@ -44,15 +44,13 @@
<dl class="card-text">
<dt i18n>Type</dt>
<dd>{{status.database.type}}</dd>
<dt i18n>URL</dt>
<dd>{{status.database.url}}</dd>
<dt i18n>Status</dt>
<dd>
{{status.database.status}}
@if (status.database.status === 'OK') {
<i-bs name="check-circle-fill" class="text-success ms-1"></i-bs>
<i-bs name="check-circle-fill" class="text-success ms-1" ngbPopover="{{status.database.url}}" triggers="mouseenter:mouseleave"></i-bs>
} @else {
<i-bs name="exclamation-triangle-fill" class="text-danger ms-1" ngbPopover="{{status.database.error}}" triggers="mouseenter:mouseleave"></i-bs>
<i-bs name="exclamation-triangle-fill" class="text-danger ms-1" ngbPopover="{{status.database.url}}: {{status.database.error}}" triggers="mouseenter:mouseleave"></i-bs>
}
</dd>
<dt i18n>Migration Status</dt>
@ -86,15 +84,13 @@
</div>
<div class="card-body">
<dl class="card-text">
<dt i18n>Redis URL</dt>
<dd>{{status.tasks.redis_url}}</dd>
<dt i18n>Redis Status</dt>
<dd>
{{status.tasks.redis_status}}
@if (status.tasks.redis_status === 'OK') {
<i-bs name="check-circle-fill" class="text-success ms-1"></i-bs>
<i-bs name="check-circle-fill" class="text-success ms-1" ngbPopover="{{status.tasks.redis_url}}" triggers="mouseenter:mouseleave"></i-bs>
} @else {
<i-bs name="exclamation-triangle-fill" class="text-danger ms-1" ngbPopover="{{status.tasks.redis_error}}" triggers="mouseenter:mouseleave"></i-bs>
<i-bs name="exclamation-triangle-fill" class="text-danger ms-1" ngbPopover="{{status.tasks.redis_url}}: {{status.tasks.redis_error}}" triggers="mouseenter:mouseleave"></i-bs>
}
</dd>
<dt i18n>Celery Status</dt>
@ -106,6 +102,30 @@
<i-bs name="exclamation-triangle-fill" class="text-danger ms-1"></i-bs>
}
</dd>
<dt i18n>Index Status</dt>
<dd>
{{status.tasks.index_status}}
@if (status.tasks.index_status === 'OK') {
<i-bs name="check-circle-fill" class="text-success ms-1" [ngbPopover]="indexStatus" triggers="mouseenter:mouseleave"></i-bs>
} @else {
<i-bs name="exclamation-triangle-fill" class="text-danger ms-1" ngbPopover="{{status.tasks.index_error}}" triggers="mouseenter:mouseleave"></i-bs>
}
</dd>
<ng-template #indexStatus>
<h6><ng-container i18n>Last Updated</ng-container>:</h6> <span class="font-monospace small">{{status.tasks.index_last_modified}}</span>
</ng-template>
<dt i18n>Classifier Status</dt>
<dd>
{{status.tasks.classifier_status}}
@if (status.tasks.classifier_status === 'OK') {
<i-bs name="check-circle-fill" class="text-success ms-1" [ngbPopover]="classifierStatus" triggers="mouseenter:mouseleave"></i-bs>
} @else {
<i-bs name="exclamation-triangle-fill" class="text-danger ms-1" ngbPopover="{{status.tasks.classifier_error}}" triggers="mouseenter:mouseleave"></i-bs>
}
</dd>
<ng-template #classifierStatus>
<h6><ng-container i18n>Last Updated</ng-container>:</h6> <span class="font-monospace small">{{status.tasks.classifier_last_modified}}</span>
</ng-template>
</dl>
</div>
</div>

View File

@ -8,29 +8,28 @@ import {
NgbActiveModal,
NgbModalModule,
NgbPopoverModule,
NgbProgressbarModule,
} from '@ng-bootstrap/ng-bootstrap'
import { Clipboard, ClipboardModule } from '@angular/cdk/clipboard'
import { SystemStatusService } from 'src/app/services/system-status.service'
import { SystemStatusDialogComponent } from './system-status-dialog.component'
import { of } from 'rxjs'
import {
PaperlessConnectionStatus,
PaperlessInstallType,
PaperlessSystemStatus,
SystemStatusItemStatus,
InstallType,
SystemStatus,
} from 'src/app/data/system-status'
import { HttpClientTestingModule } from '@angular/common/http/testing'
import { NgxBootstrapIconsModule, allIcons } from 'ngx-bootstrap-icons'
import { NgxFilesizeModule } from 'ngx-filesize'
const status: PaperlessSystemStatus = {
const status: SystemStatus = {
pngx_version: '2.4.3',
server_os: 'macOS-14.1.1-arm64-arm-64bit',
install_type: PaperlessInstallType.BareMetal,
install_type: InstallType.BareMetal,
storage: { total: 494384795648, available: 13573525504 },
database: {
type: 'sqlite',
url: '/paperless-ngx/data/db.sqlite3',
status: PaperlessConnectionStatus.ERROR,
status: SystemStatusItemStatus.ERROR,
error: null,
migration_status: {
latest_migration: 'socialaccount.0006_alter_socialaccount_extra_data',
@ -39,9 +38,15 @@ const status: PaperlessSystemStatus = {
},
tasks: {
redis_url: 'redis://localhost:6379',
redis_status: PaperlessConnectionStatus.ERROR,
redis_status: SystemStatusItemStatus.ERROR,
redis_error: 'Error 61 connecting to localhost:6379. Connection refused.',
celery_status: PaperlessConnectionStatus.ERROR,
celery_status: SystemStatusItemStatus.ERROR,
index_status: SystemStatusItemStatus.OK,
index_last_modified: new Date(),
index_error: null,
classifier_status: SystemStatusItemStatus.OK,
classifier_last_modified: new Date(),
classifier_error: null,
},
}
@ -61,6 +66,7 @@ describe('SystemStatusDialogComponent', () => {
NgxBootstrapIconsModule.pick(allIcons),
NgxFilesizeModule,
NgbPopoverModule,
NgbProgressbarModule,
],
}).compileComponents()

View File

@ -1,6 +1,6 @@
import { Component, Input } from '@angular/core'
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'
import { PaperlessSystemStatus } from 'src/app/data/system-status'
import { SystemStatus } from 'src/app/data/system-status'
import { SystemStatusService } from 'src/app/services/system-status.service'
import { Clipboard } from '@angular/cdk/clipboard'
@ -10,7 +10,7 @@ import { Clipboard } from '@angular/cdk/clipboard'
styleUrl: './system-status-dialog.component.scss',
})
export class SystemStatusDialogComponent {
public status: PaperlessSystemStatus
public status: SystemStatus
public copied: boolean = false

View File

@ -1,17 +1,17 @@
export enum PaperlessInstallType {
export enum InstallType {
Containerized = 'containerized',
BareMetal = 'bare-metal',
}
export enum PaperlessConnectionStatus {
export enum SystemStatusItemStatus {
OK = 'OK',
ERROR = 'ERROR',
}
export interface PaperlessSystemStatus {
export interface SystemStatus {
pngx_version: string
server_os: string
install_type: PaperlessInstallType
install_type: InstallType
storage: {
total: number
available: number
@ -19,7 +19,7 @@ export interface PaperlessSystemStatus {
database: {
type: string
url: string
status: PaperlessConnectionStatus
status: SystemStatusItemStatus
error?: string
migration_status: {
latest_migration: string
@ -28,8 +28,14 @@ export interface PaperlessSystemStatus {
}
tasks: {
redis_url: string
redis_status: PaperlessConnectionStatus
redis_status: SystemStatusItemStatus
redis_error: string
celery_status: PaperlessConnectionStatus
celery_status: SystemStatusItemStatus
index_status: SystemStatusItemStatus
index_last_modified: Date
index_error: string
classifier_status: SystemStatusItemStatus
classifier_last_modified: Date
classifier_error: string
}
}

View File

@ -25,7 +25,7 @@ describe('SystemStatusService', () => {
httpTestingController.verify()
})
it('calls get statys endpoint', () => {
it('calls get status endpoint', () => {
service.get().subscribe()
const req = httpTestingController.expectOne(
`${environment.apiBaseUrl}status/`

View File

@ -1,7 +1,7 @@
import { HttpClient } from '@angular/common/http'
import { Injectable } from '@angular/core'
import { Observable } from 'rxjs'
import { PaperlessSystemStatus } from '../data/system-status'
import { SystemStatus } from '../data/system-status'
import { environment } from 'src/environments/environment'
@Injectable({
@ -12,8 +12,8 @@ export class SystemStatusService {
constructor(private http: HttpClient) {}
get(): Observable<PaperlessSystemStatus> {
return this.http.get<PaperlessSystemStatus>(
get(): Observable<SystemStatus> {
return this.http.get<SystemStatus>(
`${environment.apiBaseUrl}${this.endpoint}/`
)
}

View File

@ -1,14 +1,16 @@
import os
from unittest import mock
from django.conf import settings
from django.contrib.auth.models import User
from django.test import override_settings
from rest_framework import status
from rest_framework.test import APITestCase
from paperless import version
class TestSystemStatusView(APITestCase):
class TestSystemStatus(APITestCase):
ENDPOINT = "/api/status/"
def setUp(self):
@ -67,3 +69,46 @@ class TestSystemStatusView(APITestCase):
response = self.client.get(self.ENDPOINT)
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(response.data["tasks"]["celery_status"], "OK")
@override_settings(INDEX_DIR="/tmp/index")
@mock.patch("whoosh.index.FileIndex.last_modified")
def test_system_status_index_ok(self, mock_last_modified):
mock_last_modified.return_value = 1707839087
self.client.force_login(self.user)
response = self.client.get(self.ENDPOINT)
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(response.data["tasks"]["index_status"], "OK")
self.assertIsNotNone(response.data["tasks"]["index_last_modified"])
@override_settings(INDEX_DIR="/tmp/index/")
@mock.patch("documents.index.open_index", autospec=True)
def test_system_status_index_error(self, mock_open_index):
mock_open_index.return_value = None
mock_open_index.side_effect = Exception("Index error")
self.client.force_login(self.user)
response = self.client.get(self.ENDPOINT)
mock_open_index.assert_called_once()
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(response.data["tasks"]["index_status"], "ERROR")
self.assertIsNotNone(response.data["tasks"]["index_error"])
@override_settings(MODEL_FILE="/tmp/does_not_exist")
def test_system_status_classifier_ok(self):
with open(settings.MODEL_FILE, "w") as f:
f.write("test")
f.close()
self.client.force_login(self.user)
response = self.client.get(self.ENDPOINT)
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(response.data["tasks"]["classifier_status"], "OK")
self.assertIsNone(response.data["tasks"]["classifier_error"])
@override_settings(MODEL_FILE="/tmp/does_not_exist")
@mock.patch("documents.classifier.load_classifier")
def test_system_status_classifier_error(self, mock_load_classifier):
mock_load_classifier.side_effect = Exception("Classifier error")
self.client.force_login(self.user)
response = self.client.get(self.ENDPOINT)
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(response.data["tasks"]["classifier_status"], "ERROR")
self.assertIsNotNone(response.data["tasks"]["classifier_error"])

View File

@ -35,6 +35,7 @@ from django.http import HttpResponseRedirect
from django.shortcuts import get_object_or_404
from django.utils import timezone
from django.utils.decorators import method_decorator
from django.utils.timezone import make_aware
from django.utils.translation import get_language
from django.views import View
from django.views.decorators.cache import cache_control
@ -66,6 +67,7 @@ from rest_framework.viewsets import ReadOnlyModelViewSet
from rest_framework.viewsets import ViewSet
from documents import bulk_edit
from documents import index
from documents.bulk_download import ArchiveOnlyStrategy
from documents.bulk_download import OriginalAndArchiveStrategy
from documents.bulk_download import OriginalsOnlyStrategy
@ -1595,13 +1597,39 @@ class SystemStatusView(GenericAPIView, PassUserMixin):
redis_error = "Error connecting to redis, check logs for more detail."
try:
ping = celery_app.control.inspect().ping()
first_worker_ping = ping[next(iter(ping.keys()))]
celery_ping = celery_app.control.inspect().ping()
first_worker_ping = celery_ping[next(iter(celery_ping.keys()))]
if first_worker_ping["ok"] == "pong":
celery_active = "OK"
except Exception:
celery_active = "ERROR"
index_error = None
try:
ix = index.open_index()
index_status = "OK"
index_last_modified = make_aware(
datetime.fromtimestamp(ix.last_modified()),
)
except Exception as e:
index_status = "ERROR"
index_error = "Error opening index, check logs for more detail."
logger.exception(f"System status error opening index: {e}")
index_last_modified = None
classifier_error = None
try:
load_classifier()
classifier_status = "OK"
classifier_last_modified = make_aware(
datetime.fromtimestamp(os.path.getmtime(settings.MODEL_FILE)),
)
except Exception as e:
classifier_status = "ERROR"
classifier_last_modified = None
classifier_error = "Error loading classifier, check logs for more detail."
logger.exception(f"System status error loading classifier: {e}")
return Response(
{
"pngx_version": current_version,
@ -1628,6 +1656,12 @@ class SystemStatusView(GenericAPIView, PassUserMixin):
"redis_status": redis_status,
"redis_error": redis_error,
"celery_status": celery_active,
"index_status": index_status,
"index_last_modified": index_last_modified,
"index_error": index_error,
"classifier_status": classifier_status,
"classifier_last_modified": classifier_last_modified,
"classifier_error": classifier_error,
},
},
)