Subscribe at two different priority levels?

I have one daemon that performs two tasks which need to be carried out at two different priority levels. I’m not sure how it can be implemented.

For instance, let’s say I have daemons A,B,C. Daemon A performs task A’, daemon B performs tasks B’ and B", daemon C performs task C’.

Now, I’d like the task order to be: B’, A’, C’, B".

Can this be accomplished via the priority mechanism in daemon B? Would it need two sockets? Is this possible?

On a side note, just to double check: it’s only when a daemon calls cdb.sync_subscription_socket() that the next daemon in the priority list gets notified, right?

Yes, this can be accomplished with priority mechanism. You should set priority for all subscriptions (call to cdb_subscribe) to reflect desired order. It does not matter if there is one subscription per daemon or there are several subscriptions in one daemon. From ConfD user Guide:

There can be multiple subscription points from different sources, 
that is a single client daemon can have many subscriptions and 
there can be many client daemons.

If there is more than one subscription per daemon, there can be only one subscription socket, as individual
subscriptions are identified by subscription point.

By looking at ConfD User guide, I think your assumption about cdb_sync_subscription_socket is correct. You can use cdb_sync_subscription_socket(subsock, CDB_DONE_PRIORITY).

Thanks for your reply.

To be more precise, can I subscribe to the same path with two different priorities? If so, how can I tell the priority value with which I have been notified?

hi,

every cdb_subscribe() call that you do to register subscribers, has an output “spoint” parameter.
e.g.:

int spointX;
int spointY;
cdb_subscribe(sock, 50, ns, &spointX, PATH-ABC);
cdb_subscribe(sock, 75, ns, &spointY, PATH-ABC);

further in the poll loop when processing the subscription request, you can invoke cdb_read_subscription_socket() to find out which of the daemon’s registered spoints triggered this…

pseudo code:

cdb_read_subscription_socket(sock, &sub_points, &cnt);

for (sp in sub_points):
    if (sp == spointX):
        do_stuff_for_priority_50();
    if (sp == spointY):
        do_stuff_for_priority_75();
2 Likes

Thank you so much, josephm! I finally got the hang of it. :smile:

One last thing: priorities are correctly respected except when daemons (re)start. They seem to restart without a particular order, or rather they don’t receive any notification the first time they run. Is there a way to have confd restart itself and application daemons in the same order as they receive notifications?

I see that in the confd folder there is a folder named phases, where each file corresponds a startup phase for each daemon. I don’t understand if within each phase I can define also an order of who starts first among my daemons.

Thanks again!

When application that implements some CDB subscriptions (my definition of “daemon” in this case) restarts, you can invoke cdb_trigger_subscriptions() in it, so that it receives all the data for its subscriptions (all it’s subscribers will be invoked, as if all the data is new) from database. This will follow the order defined by the priorities of subscriptions of this daemon.
You may need to handle this in multi-threaded way, as it’s blocking while all the subscriptions process their jobs… (see this procedure’s description in user guide/man page)

Thanks! So basically each of my daemons will have to call cdb_trigger_subscriptions() or only one will? I read the manual, but didn’t understand too much how exactly I can use this function.

Let’s say I have daemons A, B, C and that I want daemons to apply the part of the configuration they’re in charge of in the order A -> B-> C, where B won’t start before A finishes, and C won’t start before B finishes, just like with notifications and priorities.

A daemon will subscribe to its paths as usual, obtain subscription points, and then will call cdb_trigger_subscriptions() on these subscription points. Unless all daemons do exactly the same at the same time (not sure how), how does confd know that it has to notify A, then B, then C? I guess that if A calls that function, it will be notified in the correct order with respect to its own subscription points, and not with respect everybody else’s subscription points.

Ok, so according to the documentation for trigger_subscriptions() (python api):

The caller will trigger all subscription points passed in the sub_points
list (or all subscribers if the list is empty) in priority order

But when I run it with sub_points=, I get:

Bad protocol usage or unexpected retval (21): Unexpected OP on subscription session socket

And when I try sub_points=None:

sub_points must be a list of integers

The description of the procedures is not completely clear in user guide/man page.

A “zero” count of subscribers for the call of procedure says it will be “all” of them, but am not myself completely sure whether “all” means across any subscriber daemons, or “all that this daemon registers”.

Maybe someone else knows bit more here?

Note the “subscription session socket” part of the error message - though not spelled out in the documentation, you are not supposed to use a subscription socket for this call (that couldn’t work, since you are supposed to receive the subscription notifications on the subscription socket…). You need to connect a DATA_SOCKET and use that.

Where do you see that text? As far as I can see, both the C man page and the Python documentation clearly states that the array/list contains subscription points, and thus the “count” (in the C API) is for subscription points - there is no “count of subscribers”. And both of them say that it’s “all subscribers” if the array/list is zero length / empty. The use of “subscription points” vs “subscribers” seems clear to me - they don’t mean the same thing… See also the cdb_subscription/trigger example - it’s only C, but I believe the Python usage is pretty much the same.

right, this is the way i have used in previously; i used to interpret “subscriber” as “subscription point” - which is our course NOT correct (only loosely - in very specific implementation cases).

The “zero count” sentence is loosely incorrect transcription of the proper text you pasted from user guide (i wanted to save some time, introduced a bit of confusion).

Ok, thanks for the clarification. I got confused too.

So now I’m creating a data socket and calling trigger_subscriptions() on it. It seems to work only when I feed it the list of subscription points, but it says “Operation not implemented (51): Unknown CDB operation” when sub_points is an empty list…

import socket
import _confd
import _confd.cdb as cdb
rsock = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
cdb.connect(rsock, cdb.DATA_SOCKET, '127.0.0.1',
confd.CONFDPORT, '/')
cdb.start_session(rsock, cdb.RUNNING)
try:
    cdb.trigger_subscriptions(sock=rsock, sub_points=[])
except Exception as e:
    print("Trigger subscription failed: %s" % e)
cdb.close(rsock)

OK, this is definitely not “obviously wrong” usage (in fact what you’re doing could make a lot of sense), and pretty useless error info. The problem is the start_session() call - you should (as in the example:-) only do connect() and then trigger_subscriptions(). Once you have started a session towards RUNNING, CDB expects only “data read” operations, i.e. get(), exists(), num_instances() etc.