Skip to content

Commit 7337d17

Browse files
committed
fix(app_enabled): centralize app_enabled check
to reduce requests to nextcloud server Signed-off-by: Marcel Klehr <mklehr@gmx.net>
1 parent 531e581 commit 7337d17

3 files changed

Lines changed: 33 additions & 37 deletions

File tree

context_chat_backend/controller.py

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
# SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
33
# SPDX-License-Identifier: AGPL-3.0-or-later
44
#
5+
import time
6+
57
from nc_py_api.ex_app.providers.task_processing import TaskProcessingProvider
68

79
# isort: off
@@ -61,7 +63,20 @@
6163
'revision': '607a30d783dfa663caf39e06633721c8d4cfcd7e',
6264
}
6365
} if __download_models_from_hf else {}
66+
67+
6468
app_enabled = threading.Event()
69+
last_enabled_check: int|None = None
70+
def get_enabled_state() -> bool:
71+
global last_enabled_check
72+
if last_enabled_check is None or time.time() - last_enabled_check > 30:
73+
nc = NextcloudApp()
74+
if nc.enabled_state:
75+
app_enabled.set()
76+
else:
77+
app_enabled.clear()
78+
last_enabled_check = time.time()
79+
return app_enabled.is_set()
6580

6681
def enabled_handler(enabled: bool, nc: NextcloudApp | AsyncNextcloudApp) -> str:
6782
try:
@@ -87,7 +102,7 @@ def enabled_handler(enabled: bool, nc: NextcloudApp | AsyncNextcloudApp) -> str:
87102
if THREAD_STOP_EVENT.is_set():
88103
# If the threads were previously stopped, we start them again
89104
# otherwise the lifecycle handler has already started them
90-
start_bg_threads(app_config)
105+
start_bg_threads(app_config, get_enabled_state)
91106
THREAD_STOP_EVENT.clear()
92107
else:
93108
app_enabled.clear()
@@ -103,9 +118,8 @@ def enabled_handler(enabled: bool, nc: NextcloudApp | AsyncNextcloudApp) -> str:
103118
@asynccontextmanager
104119
async def lifespan(app: FastAPI):
105120
set_handlers(app, enabled_handler, models_to_fetch=models_to_fetch, trigger_handler=trigger_handler)
106-
start_bg_threads(app_config)
107-
nc = NextcloudApp()
108-
logger.info(f'App enable state at startup: {nc.enabled_state}')
121+
start_bg_threads(app_config, get_enabled_state)
122+
logger.info(f'App enable state at startup: {get_enabled_state()}')
109123
yield
110124
vectordb_loader.offload()
111125
wait_for_bg_threads()
@@ -192,7 +206,7 @@ def decorator(func: Callable):
192206
@wraps(func)
193207
def wrapper(*args, **kwargs):
194208
disable_aaa = app.extra['CONFIG'].disable_aaa
195-
if not disable_aaa and not app_enabled.is_set():
209+
if not disable_aaa and not get_enabled_state():
196210
return JSONResponse('Context Chat is disabled, enable it from AppAPI to use it.', 503)
197211

198212
return func(*args, **kwargs)
@@ -213,7 +227,7 @@ def _(request: Request):
213227

214228
@app.get('/enabled')
215229
def _():
216-
return JSONResponse(content={'enabled': app_enabled.is_set()}, status_code=200)
230+
return JSONResponse(content={'enabled': get_enabled_state()}, status_code=200)
217231

218232

219233
@app.post('/countIndexedDocuments')

context_chat_backend/task_fetcher.py

Lines changed: 11 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
from contextlib import suppress
1111
from enum import Enum
1212
from threading import Event, Thread
13-
from time import sleep, time
13+
from time import sleep
1414
from typing import Any
1515

1616
import niquests
@@ -69,7 +69,7 @@ class ThreadType(Enum):
6969
REQUEST_PROCESSING = 'request_processing'
7070

7171

72-
def files_indexing_thread(app_config: TConfig) -> None:
72+
def files_indexing_thread(app_config: TConfig, get_enabled_state) -> None:
7373
try:
7474
network_em = NetworkEmbeddings(app_config)
7575
vectordb_loader = VectorDBLoader(app_config)
@@ -138,18 +138,12 @@ def _load_sources(source_items: Mapping[int, SourceItem | ReceivedFileItem]) ->
138138
LOGGER.info(f'Using {file_parsing_cpu_count} parallel file parsing workers')
139139

140140
nc = NextcloudApp()
141-
last_enabled_check = time()
142-
enabled_state = nc.enabled_state
143141
while True:
144142
if THREAD_STOP_EVENT.is_set():
145143
LOGGER.info('Files indexing thread is stopping due to stop event being set')
146144
return
147145

148-
if time() - last_enabled_check > 30: # check enabled state every 30 seconds
149-
enabled_state = nc.enabled_state
150-
last_enabled_check = time()
151-
152-
if not enabled_state:
146+
if not get_enabled_state():
153147
LOGGER.info('App is disabled, files indexing thread will sleep until next enabled state check')
154148
sleep(POLLING_COOLDOWN)
155149
continue
@@ -284,26 +278,20 @@ def _load_sources(source_items: Mapping[int, SourceItem | ReceivedFileItem]) ->
284278

285279

286280

287-
def updates_processing_thread(app_config: TConfig) -> None:
281+
def updates_processing_thread(app_config: TConfig, get_enabled_state) -> None:
288282
try:
289283
vectordb_loader = VectorDBLoader(app_config)
290284
except LoaderException as e:
291285
LOGGER.error('Error initializing vector DB loader, files indexing thread will not start:', exc_info=e)
292286
return
293287

294288
nc = NextcloudApp()
295-
enabled_state = nc.enabled_state
296-
last_enabled_check = time()
297289
while True:
298290
if THREAD_STOP_EVENT.is_set():
299291
LOGGER.info('Updates processing thread is stopping due to stop event being set')
300292
return
301293

302-
if time() - last_enabled_check > 30: # check enabled state every 30 seconds
303-
enabled_state = nc.enabled_state
304-
last_enabled_check = time()
305-
306-
if not enabled_state:
294+
if not get_enabled_state():
307295
sleep(POLLING_COOLDOWN)
308296
continue
309297

@@ -475,7 +463,7 @@ def resolve_scope_list(source_ids: list[str], userId: str) -> list[str]:
475463
return ScopeList.model_validate(data).source_ids
476464

477465

478-
def request_processing_thread(app_config: TConfig) -> None:
466+
def request_processing_thread(app_config: TConfig, get_enabled_state) -> None:
479467
LOGGER.info('Starting request processing thread')
480468

481469
try:
@@ -487,8 +475,6 @@ def request_processing_thread(app_config: TConfig) -> None:
487475
return
488476

489477
nc = NextcloudApp()
490-
enabled_state = nc.enabled_state
491-
last_enabled_check = time()
492478
llm: LLM = llm_loader.load()
493479

494480
while True:
@@ -500,11 +486,7 @@ def request_processing_thread(app_config: TConfig) -> None:
500486
sleep(POLLING_COOLDOWN)
501487
continue
502488

503-
if time() - last_enabled_check > 30: # check enabled state every 30 seconds
504-
enabled_state = nc.enabled_state
505-
last_enabled_check = time()
506-
507-
if not enabled_state:
489+
if not get_enabled_state():
508490
sleep(POLLING_COOLDOWN)
509491
continue
510492

@@ -726,7 +708,7 @@ def process_search_task(
726708
)
727709

728710

729-
def start_bg_threads(app_config: TConfig):
711+
def start_bg_threads(app_config: TConfig, get_enabled_state):
730712
if APP_ROLE == AppRole.INDEXING or APP_ROLE == AppRole.NORMAL:
731713
if (
732714
ThreadType.FILES_INDEXING in THREADS
@@ -738,12 +720,12 @@ def start_bg_threads(app_config: TConfig):
738720
THREAD_STOP_EVENT.clear()
739721
THREADS[ThreadType.FILES_INDEXING] = Thread(
740722
target=files_indexing_thread,
741-
args=(app_config,),
723+
args=(app_config,get_enabled_state),
742724
name='FilesIndexingThread',
743725
)
744726
THREADS[ThreadType.UPDATES_PROCESSING] = Thread(
745727
target=updates_processing_thread,
746-
args=(app_config,),
728+
args=(app_config,get_enabled_state),
747729
name='UpdatesProcessingThread',
748730
)
749731
THREADS[ThreadType.FILES_INDEXING].start()
@@ -757,7 +739,7 @@ def start_bg_threads(app_config: TConfig):
757739
THREAD_STOP_EVENT.clear()
758740
THREADS[ThreadType.REQUEST_PROCESSING] = Thread(
759741
target=request_processing_thread,
760-
args=(app_config,),
742+
args=(app_config,get_enabled_state),
761743
name='RequestProcessingThread',
762744
)
763745
THREADS[ThreadType.REQUEST_PROCESSING].start()

context_chat_backend/utils.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import os
1010
import signal
1111
import sys
12+
import time
1213
import traceback
1314
from collections.abc import Callable
1415
from contextlib import suppress
@@ -18,7 +19,6 @@
1819
from typing import Any, TypeGuard, TypeVar
1920

2021
from fastapi.responses import JSONResponse as FastAPIJSONResponse
21-
2222
from .types import AppRole, TConfig, TEmbeddingAuthApiKey, TEmbeddingAuthBasic, TEmbeddingConfig
2323

2424
T = TypeVar('T')
@@ -313,4 +313,4 @@ def get_app_role() -> AppRole:
313313
if role not in ['indexing', 'rp']:
314314
_logger.warning(f'Invalid app role: {role}, defaulting to all roles')
315315
return AppRole.NORMAL
316-
return AppRole(role)
316+
return AppRole(role)

0 commit comments

Comments
 (0)