Skip to content

Commit 6f6f3f1

Browse files
committed
workshop: implement stickiness
Like commit 777d5b4 but for classic Workshop jobs.
1 parent 9f13e98 commit 6f6f3f1

File tree

16 files changed

+230
-13
lines changed

16 files changed

+230
-13
lines changed

debian/changelog

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
cm4all-workshop (7.7) unstable; urgency=low
22

3-
*
3+
* workshop: implement stickiness
44

55
--
66

doc/index.rst

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,25 @@ The following settings are recognized:
7878
* ``journal``: set to :samp:`yes` to send structured log
7979
messages to the systemd journal
8080

81+
* ``sticky``: if ``yes``, then jobs with the same ``sticky_id``
82+
value are always executed on the same server. This requires that
83+
all Workshop processes on all servers know each others via
84+
Zeroconf (i.e. at least ``zeroconf_service`` must be configured).
85+
See :ref:`cron.sticky` for more information.
86+
87+
* ``zeroconf_service``: discover other Workshop instances with this
88+
Zeroconf service name (for ``sticky``).
89+
* ``zeroconf_domain``: The name of the Zeroconf domain.
90+
* ``zeroconf_interface``: publish the Zeroconf service only on the
91+
given interface.
92+
* ``zeroconf_protocol``: Publish only protocol ``inet`` or
93+
``inet6``.
94+
* ``zeroconf_weight``: publish the Zeroconf service with the
95+
specified "weight", i.e. accept less or more jobs on this host.
96+
The value is a decimal number; the implied default value is
97+
:samp:`1.0`. For example, if you specify :samp:`0.5`, you expect
98+
this node to get only half as many jobs as others.
99+
81100
.. _workshop_translation_server:
82101

83102
* ``translation_server``: address the translation server is
@@ -535,6 +554,8 @@ The `jobs` table
535554
----------------
536555

537556
* ``id``: The primary key.
557+
* ``sticky_id``: An opaque string which is used to calculate
558+
:ref:`stickiness <cron.sticky>`.
538559
* ``name``: An optional name assigned by the job creator. Not
539560
used by Workshop.
540561
* ``description``: Human readable description. Not used by

sql/jobs.sql

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,11 @@ CREATE TABLE jobs (
2828
-- the management application might not know where/how exactly
2929
account_id varchar(64) NULL,
3030

31+
-- if not NULL, then use this string to calculate stickiness for
32+
-- this job (i.e. execute all jobs with the same sticky_id on the
33+
-- same cluster node)
34+
sticky_id varchar(256) NULL,
35+
3136
--------------------------------
3237
-- Execution parameters
3338
--------------------------------

src/Config.cxx

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,16 @@ WorkshopConfigParser::Partition::ParseLine(FileLineParser &line)
155155
} else if (StringIsEqual(word, "journal")) {
156156
config.enable_journal = line.NextBool();
157157
line.ExpectEnd();
158+
#ifdef HAVE_AVAHI
159+
} else if (StringIsEqual(word, "sticky")) {
160+
config.sticky = line.NextBool();
161+
line.ExpectEnd();
162+
} else if (config.zeroconf.ParseLine(word, line)) {
163+
#else
164+
} else if (StringIsEqual(word, "sticky") ||
165+
StringStartsWith(word, "zeroconf_"sv)) {
166+
throw LineParser::Error{"Zeroconf support is disabled at compile time"};
167+
#endif // HAVE_AVAHI
158168
} else
159169
throw LineParser::Error("Unknown option");
160170
}

src/Config.hxx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,10 @@ struct Config {
4848
#ifdef HAVE_AVAHI
4949
[[gnu::pure]]
5050
bool UsesZeroconf() const noexcept {
51-
return std::any_of(cron_partitions.begin(), cron_partitions.end(),
52-
[](const auto &i) { return i.UsesZeroconf(); });
51+
return std::any_of(partitions.begin(), partitions.end(),
52+
[](const auto &i) { return i.UsesZeroconf(); }) ||
53+
std::any_of(cron_partitions.begin(), cron_partitions.end(),
54+
[](const auto &i) { return i.UsesZeroconf(); });
5355
}
5456
#endif
5557
};

src/Instance.cxx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,11 @@ Instance::Instance(const Config &config,
5353

5454
for (const auto &i : config.partitions)
5555
partitions.emplace_front(*this, *library, *spawn_service,
56+
#ifdef HAVE_AVAHI
57+
avahi_client.get(),
58+
avahi_publisher.get(),
59+
avahi_error_handler,
60+
#endif // HAVE_AVAHI
5661
config, i,
5762
BIND_THIS_METHOD(OnPartitionIdle));
5863

src/Migrate.cxx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,9 @@ MigrateWorkshopDatabase(Pg::Connection &c, const char *schema)
5858
// since Workshop 7.4
5959
c.Execute("ALTER TABLE jobs ADD COLUMN IF NOT EXISTS account_id varchar(32) NULL");
6060
c.Execute("CREATE INDEX IF NOT EXISTS jobs_account_modified ON jobs(account_id, plan_name, time_modified)");
61+
62+
// since Workshop 7.7
63+
c.Execute("ALTER TABLE jobs ADD COLUMN IF NOT EXISTS sticky_id varchar(256) NULL");
6164
}
6265

6366
static void

src/workshop/Config.cxx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,9 @@ WorkshopPartitionConfig::Check() const
1111
{
1212
if (database.connect.empty())
1313
throw std::runtime_error("Missing 'database' setting");
14+
15+
#ifdef HAVE_AVAHI
16+
if (sticky && !zeroconf.IsEnabled())
17+
throw std::runtime_error{"Must configure Zeroconf if 'sticky' is enabled"};
18+
#endif
1419
}

src/workshop/Config.hxx

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,11 @@
66

77
#include "pg/Config.hxx"
88
#include "net/LocalSocketAddress.hxx"
9+
#include "config.h"
10+
11+
#ifdef HAVE_AVAHI
12+
#include "lib/avahi/ServiceConfig.hxx"
13+
#endif
914

1015
#include <string>
1116

@@ -15,6 +20,10 @@ struct WorkshopPartitionConfig {
1520
*/
1621
std::string name;
1722

23+
#ifdef HAVE_AVAHI
24+
Avahi::ServiceConfig zeroconf;
25+
#endif
26+
1827
Pg::Config database;
1928

2029
LocalSocketAddress translation_socket;
@@ -29,11 +38,22 @@ struct WorkshopPartitionConfig {
2938

3039
bool enable_journal = false;
3140

41+
#ifdef HAVE_AVAHI
42+
bool sticky = false;
43+
#endif
44+
3245
explicit WorkshopPartitionConfig(std::string &&_name) noexcept
3346
:name(std::move(_name))
3447
{
3548
translation_socket.Clear();
3649
}
3750

3851
void Check() const;
52+
53+
#ifdef HAVE_AVAHI
54+
[[gnu::pure]]
55+
bool UsesZeroconf() const noexcept {
56+
return sticky;
57+
}
58+
#endif
3959
};

src/workshop/Job.hxx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,12 @@ struct WorkshopJob {
1818

1919
std::string id, plan_name;
2020

21+
/**
22+
* An opaque string for rendezvous-hashing which determines
23+
* the Workshop node that shall execute this job.
24+
*/
25+
std::string sticky_id;
26+
2127
std::forward_list<std::string> args;
2228

2329
std::forward_list<std::string> env;

0 commit comments

Comments
 (0)