From c0fe40715744b760b42636a369cd4178c4b7e87a Mon Sep 17 00:00:00 2001 From: Piero Toffanin Date: Sat, 16 Sep 2023 12:23:49 -0400 Subject: [PATCH] Add NODE_OPTIMISTIC_MODE --- app/api/processingnodes.py | 14 +++++++++++++- app/static/app/js/components/EditTaskForm.jsx | 2 +- app/tests/test_api.py | 12 ++++++++++++ app/tests/test_app.py | 9 +++++++++ nodeodm/models.py | 3 +++ webodm/settings.py | 8 ++++++-- worker/tasks.py | 3 +++ 7 files changed, 47 insertions(+), 4 deletions(-) diff --git a/app/api/processingnodes.py b/app/api/processingnodes.py index ed37c384..9195714a 100644 --- a/app/api/processingnodes.py +++ b/app/api/processingnodes.py @@ -6,7 +6,7 @@ from rest_framework.response import Response from rest_framework.views import APIView from nodeodm.models import ProcessingNode - +from webodm import settings class ProcessingNodeSerializer(serializers.ModelSerializer): online = serializers.SerializerMethodField() @@ -49,6 +49,18 @@ class ProcessingNodeViewSet(viewsets.ModelViewSet): serializer_class = ProcessingNodeSerializer queryset = ProcessingNode.objects.all() + def list(self, request, *args, **kwargs): + queryset = self.filter_queryset(self.get_queryset()) + + if settings.UI_MAX_PROCESSING_NODES is not None: + queryset = queryset[:settings.UI_MAX_PROCESSING_NODES] + + if settings.NODE_OPTIMISTIC_MODE: + for pn in queryset: + pn.update_node_info() + + serializer = self.get_serializer(queryset, many=True) + return Response(serializer.data) class ProcessingNodeOptionsView(APIView): """ diff --git a/app/static/app/js/components/EditTaskForm.jsx b/app/static/app/js/components/EditTaskForm.jsx index 05fb7aba..64a7ae17 100644 --- a/app/static/app/js/components/EditTaskForm.jsx +++ b/app/static/app/js/components/EditTaskForm.jsx @@ -86,7 +86,7 @@ class EditTaskForm extends React.Component { } checkFilesCount(filesCount){ - if (!this.state.selectedNode) return false; + if (!this.state.selectedNode) return true; if (filesCount === 0) return true; if (this.state.selectedNode.max_images === null) return true; return this.state.selectedNode.max_images >= filesCount; diff --git a/app/tests/test_api.py b/app/tests/test_api.py index ba67721e..9e757562 100644 --- a/app/tests/test_api.py +++ b/app/tests/test_api.py @@ -460,6 +460,18 @@ class TestApi(BootTestCase): self.assertTrue(len(res.data) == 1) self.assertTrue(res.data[0]['name'] == 'a') + # Test optimistic mode + self.assertFalse(p4.is_online()) + + settings.NODE_OPTIMISTIC_MODE = True + + self.assertTrue(p4.is_online()) + res = client.get('/api/processingnodes/') + self.assertEqual(len(res.data), 3) + for nodes in res.data: + self.assertTrue(nodes['online']) + + settings.NODE_OPTIMISTIC_MODE = False def test_token_auth(self): client = APIClient() diff --git a/app/tests/test_app.py b/app/tests/test_app.py index d626dd85..d0bccd57 100644 --- a/app/tests/test_app.py +++ b/app/tests/test_app.py @@ -101,6 +101,10 @@ class TestApp(BootTestCase): self.assertEqual(res.content.decode("utf-8").count('href="/processingnode/'), 3) self.assertTemplateUsed(res, 'app/dashboard.html') + # The API should return 3 nodes + res = c.get('/api/processingnodes/') + self.assertEqual(len(res.data), 3) + # We can change that with a setting settings.UI_MAX_PROCESSING_NODES = 1 @@ -108,6 +112,11 @@ class TestApp(BootTestCase): self.assertEqual(res.content.decode("utf-8").count('href="/processingnode/'), 1) self.assertTemplateUsed(res, 'app/dashboard.html') + res = c.get('/api/processingnodes/') + self.assertEqual(len(res.data), 1) + + settings.UI_MAX_PROCESSING_NODES = None + res = c.get('/processingnode/9999/') self.assertTrue(res.status_code == 404) diff --git a/nodeodm/models.py b/nodeodm/models.py index a2f8e81e..270abf03 100644 --- a/nodeodm/models.py +++ b/nodeodm/models.py @@ -52,6 +52,9 @@ class ProcessingNode(models.Model): .order_by('queue_count').first() def is_online(self): + if settings.NODE_OPTIMISTIC_MODE: + return True + return self.last_refreshed is not None and \ self.last_refreshed >= timezone.now() - timedelta(minutes=settings.NODE_OFFLINE_MINUTES) diff --git a/webodm/settings.py b/webodm/settings.py index 6538d698..fa7b5006 100644 --- a/webodm/settings.py +++ b/webodm/settings.py @@ -389,7 +389,11 @@ CACHES = { # Number of minutes a processing node hasn't been seen # before it should be considered offline -NODE_OFFLINE_MINUTES = 5 +NODE_OFFLINE_MINUTES = 5 + +# When turned on, updates nodes information only when necessary +# and assumes that all nodes are always online, avoiding polling +NODE_OPTIMISTIC_MODE = False # URL to external auth endpoint EXTERNAL_AUTH_ENDPOINT = '' @@ -401,7 +405,7 @@ RESET_PASSWORD_LINK = '' # from an account that is exceeding a disk quota QUOTA_EXCEEDED_GRACE_PERIOD = 8 -# Maximum number of processing nodes to show in the "Processing Nodes" menu +# Maximum number of processing nodes to show in "Processing Nodes" menus/dropdowns UI_MAX_PROCESSING_NODES = None if TESTING or FLUSHING: diff --git a/worker/tasks.py b/worker/tasks.py index ca290e13..12ff4f1e 100644 --- a/worker/tasks.py +++ b/worker/tasks.py @@ -33,6 +33,9 @@ TestSafeAsyncResult = worker.celery.MockAsyncResult if settings.TESTING else app @app.task def update_nodes_info(): + if settings.NODE_OPTIMISTIC_MODE: + return + processing_nodes = ProcessingNode.objects.all() for processing_node in processing_nodes: processing_node.update_node_info()