EmbeddedRelated.com
Forums
The 2024 Embedded Online Conference

RPC/RMI in heterogeneous environments

Started by Don Y January 21, 2021
I postpone automatic type conversion to the *servant*, rather
than embedding it in the client-side stub.  My reasoning is
that this allows a wider window for the targeted node to change
*after* the RPC/RMI invocation and before it's actual servicing.

I.e., it would be silly to convert arguments for a target node
of type X, marshall them and then, before actual transport,
discover that the targeted *service* now resides on node Y
(which is of a different "character" than X).  That would require
unmarshalling the already converted arguments (the originals having
been discarded after the first conversion), converting them from X
to Y representations, remarshalling and facing the same potential
"what if it moves, again?"

However, this defers actual *checking* the data until after
transport.  It also means transport errors take a higher priority
than data type errors (cuz the data aren't checked until they've
actually been transported!)

Discussing this with colleagues, it seems a smarter approach might
be to split the activities between client- and server- side stubs.
E.g., check the data in the client-side stub so any errors in it
can be reported immediately (without waiting or relying on transport
for that to occur).  Then, let the servant sort out the details of
conversion KNOWING that the data are "valid"/correct.

[The downside of this is the servant must bear the cost of the
conversion; so, targeting an action to a resource-starved node is
costlier than it might otherwise have been.]

The process obviously mirrors for return value(s) conversions.

[I haven't, yet, considered if anything undesirable "leaks" in either
of these approaches]
On Thu, 21 Jan 2021 18:38:27 -0700, Don Y
<blockedofcourse@foo.invalid> wrote:

>I postpone automatic type conversion to the *servant*, rather >than embedding it in the client-side stub. My reasoning is >that this allows a wider window for the targeted node to change >*after* the RPC/RMI invocation and before it's actual servicing. > >I.e., it would be silly to convert arguments for a target node >of type X, marshall them and then, before actual transport, >discover that the targeted *service* now resides on node Y >(which is of a different "character" than X). That would require >unmarshalling the already converted arguments (the originals having >been discarded after the first conversion), converting them from X >to Y representations, remarshalling and facing the same potential >"what if it moves, again?"
Or it means choosing a particular 'server' before marshalling the data. Although nowadays heterogenous hardware is handled with agnostic protocols, in the past it was not unusual to use a 3-way handshake when dealing with varying hardware. The 2 sides could negotiate the protocol rather than it being fixed.
>However, this defers actual *checking* the data until after >transport. It also means transport errors take a higher priority >than data type errors (cuz the data aren't checked until they've >actually been transported!) > >Discussing this with colleagues, it seems a smarter approach might >be to split the activities between client- and server- side stubs. >E.g., check the data in the client-side stub so any errors in it >can be reported immediately (without waiting or relying on transport >for that to occur). Then, let the servant sort out the details of >conversion KNOWING that the data are "valid"/correct. > >[The downside of this is the servant must bear the cost of the >conversion; so, targeting an action to a resource-starved node is >costlier than it might otherwise have been.]
Although admittedly unusual, I can see RPC allowing, e.g., 'integer' while not requiring any particular width, or 'float' while accepting integer values and converting. It would allow the client to send whatever value it has - as long as it makes sense in context - even if the server-side function might be expecting something different. But it means either using a self describing binary protocol that encodes the type and width of each value (and also endianess if relevant) so the receiver knows what to do with it. Or it means falling back on a text-based protocol. Either way it means parsing on both sides. https://en.wikipedia.org/wiki/Comparison_of_data-serialization_formats
>The process obviously mirrors for return value(s) conversions.
In a heterogenous system, the burden of "converting" - whatever that entails - usually is placed on the more powerful processor. Of course, ordinarily the 'server' would be the more powerful processor - but in your system that's not necessarily the case. With self-describing data, each receiver can figure out what to do with what it receives. But that's going to put additional burden on low power processors ... ... unless you use dedicated comm proxies. Instead of talking directly, communication with a service hosted on a low power system is indirected through a proxy that understands and can convert between the generic RPC format and the native data format of the service's host.
>[I haven't, yet, considered if anything undesirable "leaks" in either >of these approaches]
What kind of "leaks" are you concerned with? George
Hi George,

You guys keeping safe?  I've spent the day documenting the
vaccination process for my neighbors.  Sure would have been
nice if that information was *published*!  (moronic IT
people making process decisions...)

*Snow* (dusting) expected tomorrow.  Yay!  Maybe a break
from the allergies!!  (though sad news for the citrus <shrug>)

On 1/24/2021 11:58 PM, George Neuner wrote:
> On Thu, 21 Jan 2021 18:38:27 -0700, Don Y > <blockedofcourse@foo.invalid> wrote: > >> I postpone automatic type conversion to the *servant*, rather >> than embedding it in the client-side stub. My reasoning is >> that this allows a wider window for the targeted node to change >> *after* the RPC/RMI invocation and before it's actual servicing. >> >> I.e., it would be silly to convert arguments for a target node >> of type X, marshall them and then, before actual transport, >> discover that the targeted *service* now resides on node Y >> (which is of a different "character" than X). That would require >> unmarshalling the already converted arguments (the originals having >> been discarded after the first conversion), converting them from X >> to Y representations, remarshalling and facing the same potential >> "what if it moves, again?" > > Or it means choosing a particular 'server' before marshalling the > data. Although nowadays heterogenous hardware is handled with > agnostic protocols, in the past it was not unusual to use a 3-way > handshake when dealing with varying hardware. The 2 sides could > negotiate the protocol rather than it being fixed.
The client has no control over the server; wherever the object is "backed" is where the RMI was be destined. It would be like having the ability to pick which server handles your bank account... And, as that backing can change WHILE the stub is executing (or, while a packet is waiting to gain access to the wire), the earlier you make a decision about a binding, the greater the chance of that decision needing to be "rethought" before the packet actually *hits* the wire. [I can handle these conditions but they mean another hop in the transport as a TEMPORARY zombie proxy is created on the previous hosting node to catch "late arrivals" and forward them to the new node. This just moves the goal-posts a bit. But, that zombie is intentionally short-lived just to cover the race condition] The goal in all this is to minimize the performance hit for the "local" case; if everything an app needs resides on the local node, then it shouldn't be encumbered by all this extra mechanism; just the cost of a streamlined /I/PC!
>> However, this defers actual *checking* the data until after >> transport. It also means transport errors take a higher priority >> than data type errors (cuz the data aren't checked until they've >> actually been transported!) >> >> Discussing this with colleagues, it seems a smarter approach might >> be to split the activities between client- and server- side stubs. >> E.g., check the data in the client-side stub so any errors in it >> can be reported immediately (without waiting or relying on transport >> for that to occur). Then, let the servant sort out the details of >> conversion KNOWING that the data are "valid"/correct. >> >> [The downside of this is the servant must bear the cost of the >> conversion; so, targeting an action to a resource-starved node is >> costlier than it might otherwise have been.] > > Although admittedly unusual, I can see RPC allowing, e.g., 'integer' > while not requiring any particular width, or 'float' while accepting > integer values and converting. It would allow the client to send > whatever value it has - as long as it makes sense in context - even if > the server-side function might be expecting something different.
I insist that a conversion never lose information. So, float to int is out. And, int to float can also be out (depending on the supported int values and the range of the float). But, things like Q5.3 to float can work. Or, handling a 17 bit enum in a 32b word. Or, converting a bool to a single bit. Or, an ASCIIZ string to a counted string or fixed size char array. Or, a char to a wchar. UTF16 to UTF8. "binary" to BCD, etc.
> But it means either using a self describing binary protocol that > encodes the type and width of each value (and also endianess if > relevant) so the receiver knows what to do with it. Or it means > falling back on a text-based protocol. Either way it means parsing on > both sides.
I have a dictionary of data types. Instead of just picking from a (relative) few, I let each API decide what is appropriate. The thinking being that you wouldn't FORCE an application talking to "itself" to adopt a particular subset of all available types; so, why force parts of a DECOMPOSED version of that application to adopt a similar set of constraints? In my example, a servant only needs to know how to convert all compatible incoming formats *to* the formats used by the methods it has exported. The workload manager won't migrate an object/process to a node for which converters are unavailable. E.g., Big Endian SPARC floating point likely won't have a converter to Little Endian Intel Big Rational. So, any ABI that relies on BESPARC will likely be constrained to reside on a SPARC! Unfortunately, none of the language bindings are sufficiently specific to automate these type descriptions. int_t, bcd_t, Q5_3_t, etc. may all map to the same fundamental type and, thus not gain any protections from the language.
> https://en.wikipedia.org/wiki/Comparison_of_data-serialization_formats > >> The process obviously mirrors for return value(s) conversions. > > In a heterogenous system, the burden of "converting" - whatever that > entails - usually is placed on the more powerful processor. Of > course, ordinarily the 'server' would be the more powerful processor - > but in your system that's not necessarily the case. > > With self-describing data, each receiver can figure out what to do > with what it receives. But that's going to put additional burden on > low power processors ...
...as well as overtaxed "high power" processors. If, OTOH, a datum is just tagged as "format #123" and is already known to be a valid representation of a #123 datum on the originating client, then the servant can just blindly invoke the (#123,clientflavor) to (#123,serverflavor) routine. The "parsing" is implicit. Rather than tag each datum IN TRANSIT, I let the message type reference a dictionary of "payload descriptors". Those, then, enumerate the data types and their placement in the payload.
> ... unless you use dedicated comm proxies. Instead of talking > directly, communication with a service hosted on a low power system is > indirected through a proxy that understands and can convert between > the generic RPC format and the native data format of the service's > host.
Yes. The problem, there, is being able to extricate the proxy when it is no longer needed. E.g., for Client invoking on Server, you can interpose a Proxy (possibly residing on Agent). But, as the Object backed by the Server may migrate to another (more powerful, less heavily loaded, etc.) New node, the Proxy must either stay in the loop and act as a proxy for that migrated objects, UNNECESSARILY; or, you have to remove the endpoints for that migrated Object back to the New node (replacing the existing Server endpoint that had been accessed by the Proxy). In the degenerate case, you can move all of the objects from Server to that New node and eliminate the need for the original Proxy, entirely. Then, have to eliminate the zombie proxy! [You can also fashion an "upcall" from the "dumb server" to some smart agent residing on a better endowed node. But, this starts to strain the programming model.] As the system is far from static, I envision a fair bit of object migration (which may include server migration) as more processes come on/off-line. E.g., I've noticed (in MY coding style) that a process quickly loses its need for a NameSpace as I tend to resolve any names early on in the process activation and bind them to more concrete variabes. Having no need for the NameSpace, I can "free" it and thereby lower my resource burden (which makes me look like a friendlier application to the resource scheduler). For folks who don't adopt a similar strategy (or, who can't), a NameSpace object may remain actively bound to their process for considerably longer. But, if not regularly accessed, the NameSpace server on that node may opt to move the NameSpace object to *another* NameSpace server; the object is still *active* (and accessible), but the server backing it has decided to shed those resource requirements to better serve the NameSpaces that are seeing active use! Or, the NameSpace server may be remoted by the workload scheduler to trade off resources between nodes. An infrequently accessed NameSpace could be backed on a low performance node with relative ease -- you just need enough DATA space to store the NameSpace object; access will be slower but still "correct". [Of course, *that* node could decide to migrate the NameSpace object to a BETTER processor if it sees that it is spending an inordinate amount of resources handling its requests!]
>> [I haven't, yet, considered if anything undesirable "leaks" in either >> of these approaches] > > What kind of "leaks" are you concerned with?
A process shouldn't be able to determine much about how/where it is executing *or* its affect on the rest of the system. The system decides when/where/if you should execute. And, can change those decisions without forewarning. So, anything that you think you've sussed out NOW can be invalid moments later. Or, you may cease to exist those moments later! Granted, a process could (would!) know the processor family on which it is executing (by compiling some machine-specific datum into it's image -- which might even be the command line used to invoke the compiler). If it did this frequently, it *might* be able to deduce that it has been migrated ("Hmmm... I was running on Intel and now I appear to be running on ARM") -- *if* the migration is to a different processor family (or build environment). But, it shouldn't be able to deduce its relative priority, the demand it may/maynot be placing on its hosting node, whether an object invocation is actually serviced locally or remotely, infer the load factor of the node backing that object, etc. E.g., passing bad data could leak the "localness" of the targeted node because it would incur a transport delay before being "validated" (if the checking was done in the servant). It could also leak the types of processes currently active on the targeted node as its request vs those seen on the "local" node. Due to the openness of the system, I can't count on processes being non-malevolent. Nor can I count on the hardware resources being adequate for the tasks that they are hosting at any given time. I don't want a hostile actor to be able to infer anything that could be (easily) exploited -- before the system can deduce that its a hostile actor and kill it (and blackball it so it never gets loaded, again)! I'm going to try the client/server split that was suggested in the original post and throw rocks at it to see how well it fares in a (artificially) constantly changing configuration. Then, try moving the conversions to client and/or servant and see if there is a measurable difference. Also, think harder on what each approach might leak and how that might be exploited.
Hi Don,


On Tue, 26 Jan 2021 00:06:44 -0700, Don Y
<blockedofcourse@foo.invalid> wrote:

>Hi George, > >You guys keeping safe? I've spent the day documenting the >vaccination process for my neighbors. Sure would have been >nice if that information was *published*! (moronic IT >people making process decisions...)
Arrgh! They're saying here perhaps by May. According to the news and the various national vaccination tracking sites, this state ranks near the bottom for percentage of existing doses administered (~40%). Right now, they're giving out only Pfizer's 2-dose vaccine, and there is major controversy over whether to give out more 1st doses vs completing the series for full immunization. And nobody knows how long the immunity will last anyway ... this may turn into a yearly thing like the flu. They are strictly limiting who even can get 1st doses: right now its limited to hospital workers, first responders and cowardly politicians [somehow almost the entire state legislature managed to get itself vaccinated]. They can't seem to decide what to do about 2nd doses and so far have left the decision to the individual hospitals that have vaccine to give. They've made no provisions for people to register and be notified when they are eligible - they're counting on doctors to notify their own patients !?! When was the last time your doctor called to remind you about a flu shot? I suppose I shouldn't be surprised: even in the best of times, its a rare day that the "establishment" can find its arse with both hands. These are hardly the "best of times". YMMV.
>*Snow* (dusting) expected tomorrow. Yay! Maybe a break >from the allergies!! (though sad news for the citrus <shrug>)
We've been at or below freezing for several days and we're expecting 1-2 inches of snow tonight (Tue -> Wed). We're way behind on snowfall this season.
>On 1/24/2021 11:58 PM, George Neuner wrote: >> On Thu, 21 Jan 2021 18:38:27 -0700, Don Y >> <blockedofcourse@foo.invalid> wrote: >> >>> I postpone automatic type conversion to the *servant*, rather >>> than embedding it in the client-side stub. My reasoning is >>> that this allows a wider window for the targeted node to change >>> *after* the RPC/RMI invocation and before it's actual servicing. >>> >>> I.e., it would be silly to convert arguments for a target node >>> of type X, marshall them and then, before actual transport, >>> discover that the targeted *service* now resides on node Y >>> (which is of a different "character" than X). That would require >>> unmarshalling the already converted arguments (the originals having >>> been discarded after the first conversion), converting them from X >>> to Y representations, remarshalling and facing the same potential >>> "what if it moves, again?" >> >> Or it means choosing a particular 'server' before marshalling the >> data. Although nowadays heterogenous hardware is handled with >> agnostic protocols, in the past it was not unusual to use a 3-way >> handshake when dealing with varying hardware. The 2 sides could >> negotiate the protocol rather than it being fixed. > >The client has no control over the server; wherever the object is >"backed" is where the RMI was be destined. It would be like >having the ability to pick which server handles your bank >account...
Understood. My point was about how replicated services ... ie. the same service provided by multiple servers ... are handled. The client doesn't know which server will respond to its call. In a modern system, the RPC protocol would be self describing and architecture agnostic - so it doesn't matter which server answers. However, in older systems it was not uncommon for clients to negotiate the protocol with whatever server responded, and for data in the resulting messages to be sent in the native format of one side or the other (or both, depending). Whether the client or the server (or both) did some translation was one of the points that was negotiated.
>And, as that backing can change WHILE the stub is executing (or, >while a packet is waiting to gain access to the wire), the earlier >you make a decision about a binding, the greater the chance of >that decision needing to be "rethought" before the packet >actually *hits* the wire.
Which is not the same as the problem of replicated services, but it has to be handled in a similar fashion.
>[I can handle these conditions but they mean another hop >in the transport as a TEMPORARY zombie proxy is created on >the previous hosting node to catch "late arrivals" and forward >them to the new node. This just moves the goal-posts a bit. >But, that zombie is intentionally short-lived just to cover >the race condition]
Not necessarily: a protocol that uses multicast in both directions can be completely location agnostic. But since multicast precludes directly addressing the machines, the protocol must include its own "internal" addressing scheme to identify conversations. It's common for replicated services to be on multicast, but only for initial contact by the client ... when a server responds, ordinarily it communicates directly with the client.
>The goal in all this is to minimize the performance hit for the >"local" case; if everything an app needs resides on the local >node, then it shouldn't be encumbered by all this extra mechanism; >just the cost of a streamlined /I/PC!
Which goes back to identifying the server's host before trying to communicate.
>> But [architecture agnostic] means either using a self describing >> binary protocol that encodes the type and width of each value (and >> also endianess if relevant) so the receiver knows what to do with >> it. Or it means falling back on a text-based protocol. Either >> way it means parsing on both sides. > >I have a dictionary of data types. Instead of just picking from >a (relative) few, I let each API decide what is appropriate. >The thinking being that you wouldn't FORCE an application >talking to "itself" to adopt a particular subset of all available >types; so, why force parts of a DECOMPOSED version of that application >to adopt a similar set of constraints?
Well ... RPC generally needs to be language independent. If my language has 2-3-4 tree (or, as below, "big rational") as a native type, that does not mean the RPC protocol can or should support it.
>In my example, a servant only needs to know how to convert >all compatible incoming formats *to* the formats used by the methods >it has exported. The workload manager won't migrate an object/process >to a node for which converters are unavailable. > >E.g., Big Endian SPARC floating point likely won't have a >converter to Little Endian Intel Big Rational. So, any ABI that >relies on BESPARC will likely be constrained to reside on a SPARC! > >Unfortunately, none of the language bindings are sufficiently specific >to automate these type descriptions. int_t, bcd_t, Q5_3_t, etc. >may all map to the same fundamental type and, thus not gain any >protections from the language.
Unless you design a protocol that distinguishes them.
>> https://en.wikipedia.org/wiki/Comparison_of_data-serialization_formats >> >>> The process obviously mirrors for return value(s) conversions. >> >> In a heterogenous system, the burden of "converting" - whatever that >> entails - usually is placed on the more powerful processor. Of >> course, ordinarily the 'server' would be the more powerful processor - >> but in your system that's not necessarily the case. >> >> With self-describing data, each receiver can figure out what to do >> with what it receives. But that's going to put additional burden on >> low power processors ... > >...as well as overtaxed "high power" processors. If, OTOH, a datum >is just tagged as "format #123" and is already known to be a valid >representation of a #123 datum on the originating client, then >the servant can just blindly invoke the (#123,clientflavor) to >(#123,serverflavor) routine. The "parsing" is implicit.
To a point. Absolutely, you can streamline by encoding structures and other collection types rather than individual data items. But you still have to ensure the data makes sense: e.g., that floats are not NaN or IND, that arrays have all their elements initialized, that references to nodes in serialized graphs/trees are valid, etc.
>Rather than tag each datum IN TRANSIT, I let the message type >reference a dictionary of "payload descriptors". Those, then, >enumerate the data types and their placement in the payload.
>> ... unless you use dedicated comm proxies. Instead of talking >> directly, communication with a service hosted on a low power system is >> indirected through a proxy that understands and can convert between >> the generic RPC format and the native data format of the service's >> host. > >Yes. The problem, there, is being able to extricate the proxy >when it is no longer needed. E.g., for Client invoking on Server, you >can interpose a Proxy (possibly residing on Agent). But, as the >Object backed by the Server may migrate to another (more powerful, >less heavily loaded, etc.) New node, the Proxy must either stay in >the loop and act as a proxy for that migrated objects, UNNECESSARILY; >or, you have to remove the endpoints for that migrated Object >back to the New node (replacing the existing Server endpoint that >had been accessed by the Proxy). > >In the degenerate case, you can move all of the objects from >Server to that New node and eliminate the need for the original >Proxy, entirely. Then, have to eliminate the zombie proxy! > >[You can also fashion an "upcall" from the "dumb server" to some >smart agent residing on a better endowed node. But, this starts >to strain the programming model.]
TANSTAAFL. If the scheduling model supports it, you could make a server needing a proxy into a "peer" group that must be started/stopped together.
>>> [I haven't, yet, considered if anything undesirable "leaks" in either >>> of these approaches] >> >> What kind of "leaks" are you concerned with? > >A process shouldn't be able to determine much about how/where >it is executing *or* its affect on the rest of the system. >The system decides when/where/if you should execute. And, >can change those decisions without forewarning. So, anything >that you think you've sussed out NOW can be invalid moments >later. Or, you may cease to exist those moments later! > >Granted, a process could (would!) know the processor family on >which it is executing (by compiling some machine-specific >datum into it's image -- which might even be the command >line used to invoke the compiler). If it did this frequently, >it *might* be able to deduce that it has been migrated >("Hmmm... I was running on Intel and now I appear to >be running on ARM") -- *if* the migration is to a different >processor family (or build environment). > >But, it shouldn't be able to deduce its relative priority, >the demand it may/maynot be placing on its hosting node, >whether an object invocation is actually serviced locally >or remotely, infer the load factor of the node backing that >object, etc.
If there's no way to ask ... ISTM that much of the user programming was being done in a managed language. If so, it should be (relatively) straightfoward to prevent tasks from learning about their environment.
>E.g., passing bad data could leak the "localness" of the targeted >node because it would incur a transport delay before being >"validated" (if the checking was done in the servant).
Not if there *always* is a random "transport" delay.
>It could also leak the types of processes currently active on the >targeted node as its request vs those seen on the "local" node.
Only if different errors are possible and are directly due to the difference in host.
>Due to the openness of the system, I can't count on processes >being non-malevolent. Nor can I count on the hardware resources >being adequate for the tasks that they are hosting at any given >time. I don't want a hostile actor to be able to infer anything >that could be (easily) exploited -- before the system can deduce >that its a hostile actor and kill it (and blackball it so it never >gets loaded, again)! > >I'm going to try the client/server split that was suggested in >the original post and throw rocks at it to see how well it fares >in a (artificially) constantly changing configuration. Then, >try moving the conversions to client and/or servant and see if there >is a measurable difference. > >Also, think harder on what each approach might leak and how that might >be exploited.
George
>> You guys keeping safe? I've spent the day documenting the >> vaccination process for my neighbors. Sure would have been >> nice if that information was *published*! (moronic IT >> people making process decisions...) > > Arrgh! They're saying here perhaps by May. According to the news and > the various national vaccination tracking sites, this state ranks near > the bottom for percentage of existing doses administered (~40%). > > Right now, they're giving out only Pfizer's 2-dose vaccine, and there > is major controversy over whether to give out more 1st doses vs > completing the series for full immunization. And nobody knows how > long the immunity will last anyway ... this may turn into a yearly > thing like the flu.
We have Moderna and Pfizer available, locally. WHERE you choose to receive the dose influences the choice. E.g., most "drive thru" sites are Moderna only. But, many walk-in sites are both. However, I don't see a way to determine/pick which you are going to get. If, however, you notice the timing of the second dose (you get TWO appointments when you register), you can largely deduce which it will be (i.e., if the second dose is >3, <4 weeks after the first, it is LIKELY Pfizer; >4 is likely Moderna) I fully expect this to be yet another annual vaccination (or, crap shoot if you prefer to go without). It's now endemic and we'll be hearing about it in terms much like The Hong Kong Flu, etc.
> They are strictly limiting who even can get 1st doses: right now its > limited to hospital workers, first responders and cowardly politicians > [somehow almost the entire state legislature managed to get itself > vaccinated]. They can't seem to decide what to do about 2nd doses and > so far have left the decision to the individual hospitals that have > vaccine to give.
There are all sorts of categories and sub-categories and sub-sub-categories, here. It's like looking at a classic *outline* structure: I.A.1.a.... And, there's no real priority implied by that designation! <shrug> I *think* hospitals (a couple of the sites, here, are in/at hospitals; others are "sports arena", "convention center", etc.) are trying to plan for the second shots instead of just pushing whatever they have into folks' arms. We'll see in a few weeks...
> They've made no provisions for people to register and be notified when > they are eligible - they're counting on doctors to notify their own > patients !?! When was the last time your doctor called to remind you > about a flu shot?
The "registration" part of this was the most f*cked. The state has "their way" and, of course, our county has decided that THEY have a *better* way (dunno how much is politics, NIH, etc.). You must register with the county, first. And, fill out a survey/questionnaire from which they sort out when you *should* be vaccinated. SOME TIME LATER (i.e., NOT "just after you have completed the survey" as would be typical if you'd done any OTHER on-line transaction and expected confirmation of your actions), they invite you to register for an account at the local hospital (patient portal) -- no idea how it is handled at other sites. [The patient portal seems like a hack just to get a system in place quickly without having to build from scratch] Because there is no immediate feedback/confirmation, folks try to register a second time. Or, call the phone registration hotline (for luddites). I.e., the absence of the EXPECTED sort of confirmation actually increases the cost of running the program and increases folks' anxiety about it. I have friends who have waited more than a week and still not seen any indication that their initial registration hasn't fallen into a black hole! Once "invited" to create an account, you can do so on the *hospital's* web site. Of course, it was designed with patient support in mind; not tens of thousands of connection attempts! (20,000 appointments were made in the first 2 hours) And, of course, typical IT-dweeb has *his* notion of how users should interact with "his" site. So, email address is required. As is home phone. As is cell phone. As is street address. Gender. SSN, etc. ("Gee, what if I don't *have* a home phone? Or email??") Having created an account, you can now login and schedule a vaccination appointment. Here's where things REALLY fall down... FIRST, you pick a pair of appointments (you have no choice as to the timing of the second; if you pick THIS first appointment, then you get THAT second appointment). Fine. One less thing for folks to screw up! Then, you are asked a series of questions -- one per screen. I.e., you spend a fair bit of time getting through the process. And, at the very end, when you opt to "schedule your appointment", invariably, you discover taht the time(s) you selected are "sorry, not available"! [You can understand why] But, to compound the idiocy, instead of just offering you a new list of AVAILABLE appointments, it sends you all the way back to the beginning (which was where you originally selected the appointment times). And, you progress through the same series of screens -- none of your prior answers remembered. So, invariably, is the other schmuck who got screwed out of his appointment time and is now hoping to pick the time YOU just picked as a "second choice". This continues until you realize what's happening and jump forward a few days (instead of always trying to get the "next available" times) and HOPE.
> I suppose I shouldn't be surprised: even in the best of times, its a > rare day that the "establishment" can find its arse with both hands. > These are hardly the "best of times".
The actual administration (sounds wrong in this context) of the vaccine was, by contrast, incredibly efficient! Instead of heeding the instructions to park in the remote lot and take the shuttle bus in (with a bunch of other folks packed into that small space), we drove directly to the entrance (C having worked there for many years, we are intimiately familiar with the layout of the campus, which lots are inaccessible, which often have available spots, what time of day is best, etc.). Security verifies your ID and appointment time (can't show up more than 15 minutes prior to your appointment). A pair of staff at a table ask you about allergies -- esp medications (they are only interested in IF you have any, not the details). Folks with allergies are given a tag with "30" written on it, else "15". Next desk has a couple more staff who decide to which "vaccinator" you should be routed and marks your tag accordingly. A guy escorts you to that (socially distanced) line -- no doubt to keep things moving along; I estimate 10-15 seconds between visitors. When your turn, nurse marks the time on your tag as she makes the injection. Gives you a vaccination card and instructions to keep it with you (at least until the followup shot has been administered; presumably, you won't be given the second shot if you can't prove you've had the first -- they also put a sticker on the card and want to be sure you have yours available!) Then, take a seat and wait the 15 (or 30) minutes prescribed. Meanwhile, a small army of staff circulate through the seated guests verifying everyone is OK. At the end of the required interval, you're sent out (where MOST folks would again board the kiddie bus for a drive back to their vehicles) In our case, vaccine administered exactly *1* minute after scheduled appointment. And, we were back in the car 34 minutes after that (having had to wait the 30 minutes, "supervised")
>> *Snow* (dusting) expected tomorrow. Yay! Maybe a break >>from the allergies!! (though sad news for the citrus <shrug>) > > We've been at or below freezing for several days and we're expecting > 1-2 inches of snow tonight (Tue -> Wed). We're way behind on snowfall > this season.
Last snowfall, here, in the valley, was 2 years ago. As then, we could see it falling (big fluffy flakes) but nothing "sticks". Apparently at least 18 inches on the mountain so they'll be hoping to open the ski slopes (obtrivia: southernmost ski resort in the US)
>>> Or it means choosing a particular 'server' before marshalling the >>> data. Although nowadays heterogenous hardware is handled with >>> agnostic protocols, in the past it was not unusual to use a 3-way >>> handshake when dealing with varying hardware. The 2 sides could >>> negotiate the protocol rather than it being fixed. >> >> The client has no control over the server; wherever the object is >> "backed" is where the RMI was be destined. It would be like >> having the ability to pick which server handles your bank >> account... > > Understood. My point was about how replicated services ... ie. the > same service provided by multiple servers ... are handled. The client > doesn't know which server will respond to its call. > > In a modern system, the RPC protocol would be self describing and > architecture agnostic - so it doesn't matter which server answers.
Yes. But those weren't designed as *integrated* "systems". They offered services to anyone who came along. My approach is to pull apart a system that would have resided in a big machine, had I/Os and MIPS been more accommodating.
> However, in older systems it was not uncommon for clients to negotiate > the protocol with whatever server responded, and for data in the > resulting messages to be sent in the native format of one side or the > other (or both, depending). Whether the client or the server (or > both) did some translation was one of the points that was negotiated.
I've not considered defering that decision to run-time. I make sure that the targeted node for a service CAN support the data types that its clients require. Then, the question is whether to do the conversion client- or server- -side.
>> The goal in all this is to minimize the performance hit for the >> "local" case; if everything an app needs resides on the local >> node, then it shouldn't be encumbered by all this extra mechanism; >> just the cost of a streamlined /I/PC! > > Which goes back to identifying the server's host before trying to > communicate.
I can identify local vs. remote relatively easily. And, "local" means very little payload processing so there's minimal risk of the service NOT being local when that processing is complete. But, "remote" has further complications as to *where* it is located. And, how to perform the conversion (if done before transport). E.g., if the targeted node is of the same "type" as the current node, then it is effectively the same sort of processing as the local case -- but for the introduction of the transport delay (which increases the potential for a migration to hose things up). OTOH, if the targeted node is of a different "type", the conversion costs can be higher -- more time (remember, you don't OWN the processor exclusively) and more opportunity for the world to change beneath your feet! I don't want to get into a situation where (potentially), an RMI stalls in the outbound stack because it is repeatedly massaged to adapt to a "target in motion".
>>> But [architecture agnostic] means either using a self describing >>> binary protocol that encodes the type and width of each value (and >>> also endianess if relevant) so the receiver knows what to do with >>> it. Or it means falling back on a text-based protocol. Either >>> way it means parsing on both sides. >> >> I have a dictionary of data types. Instead of just picking from >> a (relative) few, I let each API decide what is appropriate. >> The thinking being that you wouldn't FORCE an application >> talking to "itself" to adopt a particular subset of all available >> types; so, why force parts of a DECOMPOSED version of that application >> to adopt a similar set of constraints? > > Well ... RPC generally needs to be language independent. If my > language has 2-3-4 tree (or, as below, "big rational") as a native > type, that does not mean the RPC protocol can or should support it.
That's the case if you're exporting a generic sort of service. Imagine taking an Xacto knife you your existing codebase and deciding that THIS function will be remoted, but not THAT. Do you then want to have to refactor the design so the gazintas and cumzoutas are more "language neutral"? How will that impact performance? [I know of an app that treats all numerics as ASCII strings for interchange. When profiled, it spends 90+% of its time converting to and from int/float/text!]
>> In my example, a servant only needs to know how to convert >> all compatible incoming formats *to* the formats used by the methods >> it has exported. The workload manager won't migrate an object/process >> to a node for which converters are unavailable. >> >> E.g., Big Endian SPARC floating point likely won't have a >> converter to Little Endian Intel Big Rational. So, any ABI that >> relies on BESPARC will likely be constrained to reside on a SPARC! >> >> Unfortunately, none of the language bindings are sufficiently specific >> to automate these type descriptions. int_t, bcd_t, Q5_3_t, etc. >> may all map to the same fundamental type and, thus not gain any >> protections from the language. > > Unless you design a protocol that distinguishes them.
But then you can't expose them as raw types for the programmer to make use of.
>>> https://en.wikipedia.org/wiki/Comparison_of_data-serialization_formats >>> >>>> The process obviously mirrors for return value(s) conversions. >>> >>> In a heterogenous system, the burden of "converting" - whatever that >>> entails - usually is placed on the more powerful processor. Of >>> course, ordinarily the 'server' would be the more powerful processor - >>> but in your system that's not necessarily the case. >>> >>> With self-describing data, each receiver can figure out what to do >>> with what it receives. But that's going to put additional burden on >>> low power processors ... >> >> ...as well as overtaxed "high power" processors. If, OTOH, a datum >> is just tagged as "format #123" and is already known to be a valid >> representation of a #123 datum on the originating client, then >> the servant can just blindly invoke the (#123,clientflavor) to >> (#123,serverflavor) routine. The "parsing" is implicit. > > To a point. Absolutely, you can streamline by encoding structures and > other collection types rather than individual data items. But you > still have to ensure the data makes sense: e.g., that floats are not > NaN or IND, that arrays have all their elements initialized, that > references to nodes in serialized graphs/trees are valid, etc.
Yes. That was the point of "checking" the data in the client-side stub; but deferring the conversion to the server-side stub. Your implementation language wouldn't let you pass a float where an int was required. So, the RPC mechanism shouldn't let you PASS a *value* that exceeds a Q11.5 representation *if* that is what the IDL declares for that parameter.
>>>> [I haven't, yet, considered if anything undesirable "leaks" in either >>>> of these approaches] >>> >>> What kind of "leaks" are you concerned with? >> >> A process shouldn't be able to determine much about how/where >> it is executing *or* its affect on the rest of the system. >> The system decides when/where/if you should execute. And, >> can change those decisions without forewarning. So, anything >> that you think you've sussed out NOW can be invalid moments >> later. Or, you may cease to exist those moments later! >> >> Granted, a process could (would!) know the processor family on >> which it is executing (by compiling some machine-specific >> datum into it's image -- which might even be the command >> line used to invoke the compiler). If it did this frequently, >> it *might* be able to deduce that it has been migrated >> ("Hmmm... I was running on Intel and now I appear to >> be running on ARM") -- *if* the migration is to a different >> processor family (or build environment). >> >> But, it shouldn't be able to deduce its relative priority, >> the demand it may/maynot be placing on its hosting node, >> whether an object invocation is actually serviced locally >> or remotely, infer the load factor of the node backing that >> object, etc. > > If there's no way to ask ... > > ISTM that much of the user programming was being done in a managed > language. If so, it should be (relatively) straightfoward to prevent > tasks from learning about their environment.
Yes, that's true of USERLAND code. But, developers can create services that aren't in that language (for efficiency and more implementation freedom). A user can't (shouldn't) need to know if such a service is a potential security risk before opting to install it. (I don't want a closed ecosystem; and definitely don't want to have to "vet" applications). So, I try to observe behaviors at run-time and punish/ban apps that don't play well with others. This was one of the reasons I opted for the capability implementation that I chose -- instead of making services responsible for validating credentials (a bad actor could create nonsense credentials just to consume server resources; in my scheme, that happens on the "bad actor's" dime!)
>> E.g., passing bad data could leak the "localness" of the targeted >> node because it would incur a transport delay before being >> "validated" (if the checking was done in the servant). > > Not if there *always* is a random "transport" delay.
But you want to be able to host a service locally to gain efficiency; you wouldn't want to deliberately insert a (variable) delay just to make the client THINK it might be interacting with a remote server. Of course, the fact that that server can *move* means any information you glean from your interactions NOW may be invalid a moment later.
>> It could also leak the types of processes currently active on the >> targeted node as its request vs those seen on the "local" node. > > Only if different errors are possible and are directly due to the > difference in host.
Hence the checking on client side. E.g., if I can pass 199999Q44 to an RPC that expects a Q10.2 datum -- knowing it is invalid -- and get a response that I can KNOW incurs a transport delay (because I know that the checking is done at the server end), then I can profile the transport delay. If, OTOH, that error is generated locally BEFORE transport, then there's no point in throwing bogus values at it. Note that I can't "see" anything happening in the stubs. So, I can't see if you're being an *sshole and take measures to counter your actions. Once something passes through the transport layer, the far-side server can see the action and decide to drop the endpoint (effectively barring you from using its services). So, if you try to hammer on a service, the service can just stop responding to your actions -- effectively blocking your execution (sync calls).
On Tue, 26 Jan 2021 13:39:30 -0700, Don Y
<blockedofcourse@foo.invalid> wrote:


>>> The client has no control over the server; wherever the object is >>> "backed" is where the RMI was be destined. It would be like >>> having the ability to pick which server handles your bank >>> account... >> >> Understood. My point was about how replicated services ... ie. the >> same service provided by multiple servers ... are handled. The client >> doesn't know which server will respond to its call. >> >> In a modern system, the RPC protocol would be self describing and >> architecture agnostic - so it doesn't matter which server answers. > >Yes. But those weren't designed as *integrated* "systems". They >offered services to anyone who came along. My approach is to >pull apart a system that would have resided in a big machine, had I/Os >and MIPS been more accommodating.
You're not seeing that the case where a service may change hosts is quite similar to the case where the service can be provided by multiple hosts. In either case, the client does not know which host will answer until it tries to communicate.
>> However, in older systems it was not uncommon for clients to negotiate >> the protocol with whatever server responded, and for data in the >> resulting messages to be sent in the native format of one side or the >> other (or both, depending). Whether the client or the server (or >> both) did some translation was one of the points that was negotiated. > >I've not considered defering that decision to run-time. I >make sure that the targeted node for a service CAN support the >data types that its clients require. Then, the question is >whether to do the conversion client- or server- -side.
Perhaps it is time to look into such a run-time solution.
>>> The goal in all this is to minimize the performance hit for the >>> "local" case; if everything an app needs resides on the local >>> node, then it shouldn't be encumbered by all this extra mechanism; >>> just the cost of a streamlined /I/PC! >> >> Which goes back to identifying the server's host before trying to >> communicate. > >I can identify local vs. remote relatively easily. And, "local" >means very little payload processing so there's minimal risk >of the service NOT being local when that processing is complete. > >But, "remote" has further complications as to *where* it is >located. And, how to perform the conversion (if done before >transport). > >E.g., if the targeted node is of the same "type" as the current >node, then it is effectively the same sort of processing as the >local case -- but for the introduction of the transport delay >(which increases the potential for a migration to hose things up). > >OTOH, if the targeted node is of a different "type", the conversion >costs can be higher -- more time (remember, you don't OWN the processor >exclusively) and more opportunity for the world to change beneath your >feet! > >I don't want to get into a situation where (potentially), an RMI >stalls in the outbound stack because it is repeatedly massaged to >adapt to a "target in motion".
But what is the likelihood of that? You have said that the server can only be started on a CPU that has sufficient resources ... so apart from a failure WHY would it be started somewhere and then quickly moved somewhere else? If you are anticipating that clients routinely will spend so much time in their local RPC code that a useful service has time to be rehosted ... well then you've got bigger problems than servers moving.
>[I know of an app that treats all numerics as ASCII strings for >interchange. When profiled, it spends 90+% of its time converting >to and from int/float/text!]
I *wrote* such an application: the spec required that all network communications be human readable. In my case, however, there was a large amount of processing being done at all nodes, so although the messaging was complicated by printing and parsing, altogether it consumed only a small percentage of CPU time. George
On Thu, 21 Jan 2021 18:38:27 -0700, Don Y
<blockedofcourse@foo.invalid> wrote:

>I postpone automatic type conversion to the *servant*, rather >than embedding it in the client-side stub. My reasoning is >that this allows a wider window for the targeted node to change >*after* the RPC/RMI invocation and before it's actual servicing.
You must be quite desperate (extreme data rate, flea power client, very small memory client) for even considering functionality that naturally belongs to the client. Any healthy clients can handle byte order, time zones, character sets and languages.
On 1/28/2021 7:08 PM, George Neuner wrote:
> On Tue, 26 Jan 2021 13:39:30 -0700, Don Y > <blockedofcourse@foo.invalid> wrote: > >>>> The client has no control over the server; wherever the object is >>>> "backed" is where the RMI was be destined. It would be like >>>> having the ability to pick which server handles your bank >>>> account... >>> >>> Understood. My point was about how replicated services ... ie. the >>> same service provided by multiple servers ... are handled. The client >>> doesn't know which server will respond to its call. >>> >>> In a modern system, the RPC protocol would be self describing and >>> architecture agnostic - so it doesn't matter which server answers. >> >> Yes. But those weren't designed as *integrated* "systems". They >> offered services to anyone who came along. My approach is to >> pull apart a system that would have resided in a big machine, had I/Os >> and MIPS been more accommodating. > > You're not seeing that the case where a service may change hosts is > quite similar to the case where the service can be provided by > multiple hosts. In either case, the client does not know which host > will answer until it tries to communicate.
It's not applicable in my world. The client NEVER knows which host (which may be its own!) *will* service or *did* service a particular request because the client never knows where the object resides, at any point in time. The *kernel* does the actual transaction as it knows whether your handle ACTUALLY references an object of that "type" (a handle is just an int), which permissions you have for the object's methods, where the object is "physically" located, etc. (if those tests were done in the client's address space, the client could bypass them) "You" don't see the RMI as anything other than an expensive function invocation. You aren't involved in deciding how -- or where -- the action is performed; all you get to see is the result(s) of that invocation (or a data error or transport failure).
>>> However, in older systems it was not uncommon for clients to negotiate >>> the protocol with whatever server responded, and for data in the >>> resulting messages to be sent in the native format of one side or the >>> other (or both, depending). Whether the client or the server (or >>> both) did some translation was one of the points that was negotiated. >> >> I've not considered defering that decision to run-time. I >> make sure that the targeted node for a service CAN support the >> data types that its clients require. Then, the question is >> whether to do the conversion client- or server- -side. > > Perhaps it is time to look into such a run-time solution.
That's done at compile time (sorting out how to do the conversions) and at run time by the workload manager knowing which nodes are running which servers, on which types of hardware/processors, with what resource complements, etc. There's no "negotiation" involved; the workload manager simply conditions its selection of the "best" node on which to place a server based on the data types that will be required (if sited, there) and the conversion routines available for its clients.
>>>> The goal in all this is to minimize the performance hit for the >>>> "local" case; if everything an app needs resides on the local >>>> node, then it shouldn't be encumbered by all this extra mechanism; >>>> just the cost of a streamlined /I/PC! >>> >>> Which goes back to identifying the server's host before trying to >>> communicate. >> >> I can identify local vs. remote relatively easily. And, "local" >> means very little payload processing so there's minimal risk >> of the service NOT being local when that processing is complete. >> >> But, "remote" has further complications as to *where* it is >> located. And, how to perform the conversion (if done before >> transport). >> >> E.g., if the targeted node is of the same "type" as the current >> node, then it is effectively the same sort of processing as the >> local case -- but for the introduction of the transport delay >> (which increases the potential for a migration to hose things up). >> >> OTOH, if the targeted node is of a different "type", the conversion >> costs can be higher -- more time (remember, you don't OWN the processor >> exclusively) and more opportunity for the world to change beneath your >> feet! >> >> I don't want to get into a situation where (potentially), an RMI >> stalls in the outbound stack because it is repeatedly massaged to >> adapt to a "target in motion". > > But what is the likelihood of that? You have said that the server can > only be started on a CPU that has sufficient resources ... so apart > from a failure WHY would it be started somewhere and then quickly > moved somewhere else?
It may have been started 4 hours ago; that doesn't change the fact that there is a (possibly large) window between when the RMI is invoked and when the message actually hits the wire, destined for some PARTICULAR node (which may now be incorrect, given the data type conversions that were applied to the parameters WHEN INVOKED). The *tough* failures are "someone unplugged node #37" (or powered it down, unintentionally). Suddenly EVERYTHING that was running on that node is *gone*. And, every reference INTO that node (as well as out of) is now meaningless, on every node in the system! Because a node can easily host hundreds/thousands of objects, there is a flurry of activity (within a node and between nodes) when a node goes down so unceremoniously. [It's actually entertaining to watch things move around, new nodes get powered up, etc.] So, the system sees a spike in utilization as it tries to recover. That increases the likelihood of deadlines not being met. Which, in turn, brings about more exception handling. And, services deciding to simply quit (HRT) -- which propagates to clients who expected those services to be "up", etc. [The challenge is ensuring this doesn't become chaotic] As this isn't "normal" operation, the workload manager can't know what sort of NEW load factors will exist as they ALL try to recover from their missed deadline(s), broken RMIs, dropped endpoints, etc. It can only react after the fact. *Then*, start reshuffling objects to eliminate peaks. If someone unplugged a node "improperly" (the most likely catastrophic "failure") without telling the system that they WANTED to do so, then it is also likely that they may soon unplug ANOTHER node (e.g., "Ooops! Wrong cord! Maybe it's THIS one?") [I've put a lot of effort into making it easier for Joe Average User to Do-The-Right-Thing (*if* it needs to be done, at all) when it comes to physical system configuration. But, he'd quickly be intimidated if a simple error on his part ("Wrong cord") resulted in significant consequences (e.g., system reboot).] [[In other applications, users may be prevented from tinkering with the physical system by policy ("touch this and you're fired!") or physical barriers (locked equipment closet). I don't have that luxury in *my* application. And, no IT department to attend to these acts.]] There are also other "normal use cases" that result in a lot of dynamic reconfiguration. E.g., if power fails, the system has to start shedding load (powering down nodes that it deems nonessential). Doing that means those resources have to be shuffled to other nodes that will remain "up" -- at least until the next load shedding threshold (to prolong battery life). And, competing with users who may have their own ideas as to how to shift the load to address the power outage. And, of course, the normal acquiring and shedding of applications on the whims of users varies the instantaneous load on the system... which precipitates load balancing activities. Bottom line, things are ALWAYS jostling around.
> If you are anticipating that clients routinely will spend so much time > in their local RPC code that a useful service has time to be rehosted > ... well then you've got bigger problems than servers moving.
I expect a *lot* of service invocations as EVERYTHING is an object (thus backed by a service). Applications just wire together services. The system sorts out how best to address the *current* demands being placed on it. In ages past, you'd just keep throwing a bigger and bigger processor at the problem as more "responsibilities" got added. And, in periods of less-than-peak demand, you'd bear the cost of an overprovisioned system. Eventually, you'd realize you couldn't continue scaling in this manner and would opt for additional processor(s). Then, you'd start sorting out how to partition the (existing!) system. And, how to rebuild applications to handle the introduction of new communication protocols between components on different processors. [One of my colleagues is working on an app that sprawls over close to a square mile!]
>> [I know of an app that treats all numerics as ASCII strings for >> interchange. When profiled, it spends 90+% of its time converting >> to and from int/float/text!] > > I *wrote* such an application: the spec required that all network > communications be human readable. In my case, however, there was a > large amount of processing being done at all nodes, so although the > messaging was complicated by printing and parsing, altogether it > consumed only a small percentage of CPU time.
Different sort of application. I've designed several "english" language interfaces that were unnecessarily verbose to make them more portable and understandable. The "unnecessary text" and encodings acted to enhance confidence in the integrity of the comms protocol. But, even manually enforcing all of the "superfluous" text is trivial in those and represents window dressing instead of an encumbrance to the passing of the actual data. "Sample in cell C2 has identifier 177D6BB.\n" Imagine, instead: sum = fmul("1003.45", "-3348234.0002") The Chinese Meal! :>
On 1/29/2021 11:33 AM, upsidedown@downunder.com wrote:
> On Thu, 21 Jan 2021 18:38:27 -0700, Don Y > <blockedofcourse@foo.invalid> wrote: > >> I postpone automatic type conversion to the *servant*, rather >> than embedding it in the client-side stub. My reasoning is >> that this allows a wider window for the targeted node to change >> *after* the RPC/RMI invocation and before it's actual servicing. > > You must be quite desperate (extreme data rate, flea power client, > very small memory client) for even considering functionality that > naturally belongs to the client.
It's "power" (resource) related only in that time = 1/"power"
> Any healthy clients can handle byte order, time zones, character sets > and languages.
Convert Q10.6 to double
On Thu, 21 Jan 2021 18:38:27 -0700, Don Y
<blockedofcourse@foo.invalid> wrote:

>I postpone automatic type conversion to the *servant*, rather >than embedding it in the client-side stub. My reasoning is >that this allows a wider window for the targeted node to change >*after* the RPC/RMI invocation and before it's actual servicing. > >I.e., it would be silly to convert arguments for a target node >of type X, marshall them and then, before actual transport, >discover that the targeted *service* now resides on node Y >(which is of a different "character" than X). That would require >unmarshalling the already converted arguments (the originals having >been discarded after the first conversion), converting them from X >to Y representations, remarshalling and facing the same potential >"what if it moves, again?" > >However, this defers actual *checking* the data until after >transport. It also means transport errors take a higher priority >than data type errors (cuz the data aren't checked until they've >actually been transported!) > >Discussing this with colleagues, it seems a smarter approach might >be to split the activities between client- and server- side stubs. >E.g., check the data in the client-side stub so any errors in it >can be reported immediately (without waiting or relying on transport >for that to occur). Then, let the servant sort out the details of >conversion KNOWING that the data are "valid"/correct. > >[The downside of this is the servant must bear the cost of the >conversion; so, targeting an action to a resource-starved node is >costlier than it might otherwise have been.] > >The process obviously mirrors for return value(s) conversions. > >[I haven't, yet, considered if anything undesirable "leaks" in either >of these approaches]
Dud you look at the MQTT protocol https://en.wikipedia.org/wiki/MQTT which is often used with the IoT drivel. The MQTT Broker handles the marshaling between lightweight clients.

The 2024 Embedded Online Conference