larxius commited on
Commit
d8154b5
·
verified ·
1 Parent(s): eb44e60

Update backend_structured/scanners_core.py

Browse files
Files changed (1) hide show
  1. backend_structured/scanners_core.py +65 -17
backend_structured/scanners_core.py CHANGED
@@ -73,7 +73,7 @@ import jwt
73
  import math
74
  import os
75
  import re
76
- import re, time, ipaddress, os, hashlib, threading
77
  import requests
78
  import socket
79
  import sqlite3
@@ -762,31 +762,79 @@ if CELERY_AVAILABLE and celery:
762
  run_background_scan_task.delay(new_scan.id)
763
 
764
 
765
- # ── Thread-based launcher (always available, no Redis required) ───────────────
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
766
 
767
  def launch_scan(app, scan_id: str) -> bool:
768
  """
769
- Launch a scan using threading or Celery.
770
- Defaults to fast background threading unless USE_CELERY=true is explicitly set.
 
771
  """
 
 
772
  use_celery = os.getenv('USE_CELERY', 'false').lower() == 'true'
773
  if use_celery and CELERY_AVAILABLE and celery:
774
  run_background_scan_task.delay(scan_id)
775
  print(f"[Scanner] Background scan dispatched to Celery for scan {scan_id}", flush=True)
776
  return True
777
-
778
- print(f"[Scanner] Spawning background scan thread for scan {scan_id}...", flush=True)
779
- def thread_target(application, sid):
780
- with application.app_context():
781
- try:
782
- _run_scan_job(sid)
783
- except Exception as ex:
784
- print(f"[Scanner] Background thread crashed for scan {sid}: {ex}", flush=True)
785
- traceback.print_exc()
786
-
787
- thread = threading.Thread(target=thread_target, args=(app, scan_id), daemon=True)
788
- thread.start()
789
- print(f"[Scanner] Background thread started for scan {scan_id}", flush=True)
 
 
 
 
 
 
 
 
 
 
 
 
790
  return True
791
 
792
 
 
73
  import math
74
  import os
75
  import re
76
+ import re, time, ipaddress, os, hashlib, threading, queue
77
  import requests
78
  import socket
79
  import sqlite3
 
762
  run_background_scan_task.delay(new_scan.id)
763
 
764
 
765
+ # ── Thread-based launcher with Sequential FIFO Queue (One scan at a time) ──
766
+
767
+ _scan_queue = queue.Queue()
768
+ _queue_worker_started = False
769
+ _queue_lock = threading.Lock()
770
+
771
+ def _scan_queue_worker(app):
772
+ print("[ScanQueueWorker] Sequential background worker thread started.", flush=True)
773
+ while True:
774
+ try:
775
+ sid = _scan_queue.get()
776
+ if sid is None:
777
+ break
778
+
779
+ print(f"[ScanQueueWorker] Beginning execution of queued scan {sid}...", flush=True)
780
+ with app.app_context():
781
+ try:
782
+ s = Scan.query.get(sid)
783
+ if s:
784
+ s.status = 'scanning'
785
+ s.started_at = datetime.now(timezone.utc)
786
+ db.session.commit()
787
+ add_log(sid, f"[INFO] Target: {s.target_url} ({s.scan_type} Scan)")
788
+ add_log(sid, "[INFO] Sequential scan worker starting active audit execution...")
789
+
790
+ _run_scan_job(sid)
791
+ except Exception as ex:
792
+ print(f"[ScanQueueWorker] Error executing scan {sid}: {ex}", flush=True)
793
+ traceback.print_exc()
794
+ finally:
795
+ _scan_queue.task_done()
796
+ except Exception as e:
797
+ print(f"[ScanQueueWorker] Queue worker exception: {e}", flush=True)
798
+ time.sleep(1)
799
 
800
  def launch_scan(app, scan_id: str) -> bool:
801
  """
802
+ Launch a scan using a sequential FIFO queue.
803
+ Ensures only ONE active scan executes at any given time.
804
+ Subsequent scans wait in 'queued' state and run automatically when the current scan finishes.
805
  """
806
+ global _queue_worker_started
807
+
808
  use_celery = os.getenv('USE_CELERY', 'false').lower() == 'true'
809
  if use_celery and CELERY_AVAILABLE and celery:
810
  run_background_scan_task.delay(scan_id)
811
  print(f"[Scanner] Background scan dispatched to Celery for scan {scan_id}", flush=True)
812
  return True
813
+
814
+ with app.app_context():
815
+ try:
816
+ s = Scan.query.get(scan_id)
817
+ if s:
818
+ active_scan = Scan.query.filter(Scan.status == 'scanning', Scan.id != scan_id).first()
819
+ if active_scan or not _scan_queue.empty():
820
+ s.status = 'queued'
821
+ print(f"[Scanner] Active scan in progress ({active_scan.id if active_scan else 'queued item'}). Setting scan {scan_id} to queued.", flush=True)
822
+ else:
823
+ s.status = 'scanning'
824
+ s.started_at = datetime.now(timezone.utc)
825
+ print(f"[Scanner] Queue empty. Setting scan {scan_id} directly to scanning.", flush=True)
826
+ db.session.commit()
827
+ except Exception as err:
828
+ print(f"[Scanner] Failed updating scan status on launch: {err}", flush=True)
829
+
830
+ with _queue_lock:
831
+ if not _queue_worker_started:
832
+ worker_thread = threading.Thread(target=_scan_queue_worker, args=(app,), daemon=True)
833
+ worker_thread.start()
834
+ _queue_worker_started = True
835
+
836
+ _scan_queue.put(scan_id)
837
+ print(f"[Scanner] Scan {scan_id} placed in execution queue (Current queue size: {_scan_queue.qsize()})", flush=True)
838
  return True
839
 
840