Repository: google/fuzzbench

Issue:
worker mode change
Currently, we use brust mode for all workers.
However, this may let some workers quickly down when there is nothing to do temporarily.
For example, when one job is worked by worker A, and all other jobs are deferred or finished, then all other workers will exit.

I guess, we still need these workers on until all jobs finish.


Discussion:
This will also introduce uncertain behavior for end-to-end testing in Github CI test.
One solution is to remove the brust mode setting, and shutdown workers from the `fuzzbench/run_experiment.py` when all jobs are finished or one job is failed.
> One solution is to remove the brust mode setting, and shutdown workers from the `fuzzbench/run_experiment.py` when all jobs are finished or one job is failed.

Sounds good to me.

Resolving patch:
diff --git a/fuzzbench/run_experiment.py b/fuzzbench/run_experiment.py
--- a/fuzzbench/run_experiment.py
+++ b/fuzzbench/run_experiment.py
@@ -24,19 +24,14 @@
 def run_experiment():
     """Main experiment logic."""
     print('Initializing the job queue.')
-    queue = rq.Queue()
+    # Create the queue for scheduling build jobs and run jobs.
+    queue = rq.Queue('build_n_run_queue')
     jobs_list = []
     jobs_list.append(
         queue.enqueue(jobs.build_image,
                       'base-image',
                       job_timeout=600,
                       job_id='base-image'))
-    jobs_list.append(
-        queue.enqueue(jobs.build_image,
-                      'base-builder',
-                      job_timeout=600,
-                      job_id='base-builder',
-                      depends_on='base-image'))
     jobs_list.append(
         queue.enqueue(jobs.build_image,
                       'base-runner',
diff --git a/fuzzbench/worker.py b/fuzzbench/worker.py
new file mode 100644
--- /dev/null
+++ b/fuzzbench/worker.py
@@ -0,0 +1,34 @@
+# Copyright 2020 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+"""Self-defined worker module."""
+import time
+
+import redis
+import rq
+
+
+def main():
+    """Sets up Redis connection and starts the worker."""
+    redis_connection = redis.Redis(host="queue-server")
+    with rq.Connection(redis_connection):
+        queue = rq.Queue('build_n_run_queue')
+        worker = rq.Worker([queue])
+
+        while queue.count + queue.deferred_job_registry.count > 0:
+            worker.work(burst=True)
+            time.sleep(5)
+
+
+if __name__ == '__main__':
+    main()


Test patch:
diff --git a/experiment/build/test_docker_images.py b/experiment/build/test_docker_images.py
--- a/experiment/build/test_docker_images.py
+++ b/experiment/build/test_docker_images.py
@@ -23,7 +23,7 @@ def test_images_to_build_list():
     benchmarks = ['libxml', 'libpng']
     all_images = docker_images.get_images_to_build(fuzzers, benchmarks)
     assert set(all_images.keys()) == set([
-        'base-image', 'base-builder', 'base-runner', 'coverage-builder',
+        'base-image', 'base-runner', 'coverage-builder',
         'coverage-libxml-builder', 'coverage-libpng-builder', 'afl-builder',
         'afl-libxml-builder', 'afl-libxml-intermediate-runner',
         'afl-libxml-runner', 'afl-libpng-builder',
diff --git a/fuzzbench/test_e2e_run.py b/fuzzbench/test_e2e_run.py
--- a/fuzzbench/test_e2e_run.py
+++ b/fuzzbench/test_e2e_run.py
@@ -39,14 +39,13 @@ def test_jobs_dependency(self, redis_connection):  # pylint: disable=redefined-o
         """Tests that jobs dependency preserves during working."""
         jobs = {
             name: Job.fetch(name, connection=redis_connection)
-            for name in ['base-image', 'base-builder', 'base-runner']
+            for name in ['base-image', 'base-runner']
         }
-        assert jobs['base-image'].ended_at <= jobs['base-builder'].started_at
         assert jobs['base-image'].ended_at <= jobs['base-runner'].started_at
 
     def test_all_jobs_finished_successfully(self, redis_connection):  # pylint: disable=redefined-outer-name
         """Tests all jobs finished successully."""
-        jobs = Job.fetch_many(['base-image', 'base-builder', 'base-runner'],
+        jobs = Job.fetch_many(['base-image', 'base-runner'],
                               connection=redis_connection)
         for job in jobs:
             assert job.get_status() == 'finished'