diff --git a/docs/setup_rabbitmq.md b/docs/setup_rabbitmq.md index 5b3e8c20..3debbee3 100644 --- a/docs/setup_rabbitmq.md +++ b/docs/setup_rabbitmq.md @@ -55,6 +55,8 @@ As root, I would create a file in `/var/log/gEAR_queue` named `.log` wh ## Running a particular consumer +NOTE: This is automatically handled in the projectr_consumer system.d service file + First, make sure a directory is present under /var/log/gEAR_queue (you may have to create this as root). If you are not going to run the consumer listener as root, ensure the user has the same group-write privileges as the directory. The consumer scripts are stored at `/listeners/`. Let it run in the background (preferably with `nohup`) diff --git a/systemd/README.md b/systemd/README.md new file mode 100644 index 00000000..5a4e0e5a --- /dev/null +++ b/systemd/README.md @@ -0,0 +1,17 @@ +# system.d files + +These are service files to place in `/etc/systemd/system/` to run as a service. + +The "@" in the service file name indicates that this file is a template file. You can spawn off workers off of this template by appending numbers after the "@". For instance, if you have a "worker@.service" template, you can spawn off "worker@2.service", "worker@2.service", etc. You can also just use the ".target" file to group all these workers together as a service rather than having to start each indiviudally. See https://www.stevenrombauts.be/2019/01/run-multiple-instances-of-the-same-systemd-unit/ for more info on all this. + +## Non-persisting start + +To start the service run `sudo systemctl start `. If any changes are made to the service run `sudo systemctl daemon-reload`, and then run the "start" command again. This will not persist during a reboot. + +## Reboot-persisting start + +To start a service that persists during a reboot, run `sudo systemctl enable `. After enabling, you will still need to run the `systemctl start` command to start on this boot session. + +## Notes + +* For a service that is supposed to persist, like a RabbitMQ consumer, use Service->Type=Simple. If you use Type->Forking, I believe systemctl will forever wait for the forked process to exit and return to command line. \ No newline at end of file diff --git a/systemd/projectr-consumer.target b/systemd/projectr-consumer.target new file mode 100644 index 00000000..3b52e2a9 --- /dev/null +++ b/systemd/projectr-consumer.target @@ -0,0 +1,6 @@ +[Unit] +Description=ProjectR Consumer Workers +Wants=projectr-consumer@1.service projectr-consumer@2.service projectr-consumer@3.service + +[Install] +WantedBy=multi-user.target \ No newline at end of file diff --git a/systemd/projectr-consumer@.service b/systemd/projectr-consumer@.service new file mode 100644 index 00000000..271c6765 --- /dev/null +++ b/systemd/projectr-consumer@.service @@ -0,0 +1,17 @@ +[Unit] +Description="ProjectR Consumer for RabbitMQ - #%i" +Documentation=https://github.com/IGS/gEAR/blob/main/docs/setup_rabbitmq.md +After=rabbitmq-server.service + +[Service] +Type=simple +Environment=APACHE_STARTED_BY_SYSTEMD=true +ExecStart=/opt/bin/python3 /home/jorvis/git/gEAR/listeners/projectr_consumer.py +KillMode=mixed +PrivateTmp=true +Restart=always +RestartSec=2s +StartLimitIntervalSec=0 + +[Install] +WantedBy=multi-user.target \ No newline at end of file diff --git a/www/js/curator_common.js b/www/js/curator_common.js index bfb18c29..edcc2294 100644 --- a/www/js/curator_common.js +++ b/www/js/curator_common.js @@ -1202,7 +1202,7 @@ const renderOrderSortableSeries = (series) => { } // Create sortable for this series - sortable(`#${series}-order-list`, { + sortable(`#${CSS.escape(series)}-order-list`, { hoverClass: "has-text-weight-bold" , itemSerializer(item, container) { item.label = item.node.textContent @@ -1494,10 +1494,11 @@ const updateOrderSortable = () => { } // Get all current plotting order series and save as a set - const sortableElts = document.querySelectorAll(".js-plot-order-sortable p"); + // selector syntax from https://tobiasahlin.com/blog/previous-sibling-css-has/ + const sortableElts = document.querySelectorAll("p:has(+ .js-plot-order-sortable)"); const sortableSet = new Set(); for (const elt of sortableElts) { - const series = elt.value; + const series = elt.textContent; // These series already are categorical if (series) { sortableSet.add(series); @@ -1510,7 +1511,7 @@ const updateOrderSortable = () => { } for (const series of sortableSet) { - // 3. Series is in sortableSet but not seriesSet, remove -order element + // Series is in sortableSet but not seriesSet, remove -order element if (!seriesSet.has(series)) { const orderElt = document.getElementById(`${series}-order`); orderElt.remove();