Package io.mats3
Class MatsInitiator.MatsInitiateWrapper
java.lang.Object
io.mats3.MatsInitiator.MatsInitiateWrapper
- All Implemented Interfaces:
MatsFactory.MatsWrapper<MatsInitiator.MatsInitiate>
,MatsInitiator.MatsInitiate
- Enclosing interface:
- MatsInitiator
public static class MatsInitiator.MatsInitiateWrapper
extends Object
implements MatsFactory.MatsWrapper<MatsInitiator.MatsInitiate>, MatsInitiator.MatsInitiate
A base Wrapper for
MatsInitiator.MatsInitiate
, which simply implements MatsInitiate, takes a MatsInitiate instance and
forwards all calls to that. Use this if you need to wrap the MatsInitiate, where most of the methods are
pass-through to the target, as any changes to the MatsInitiate interface then won't break your wrapper.-
Constructor Summary
ConstructorsConstructorDescriptionNo-args constructor, which implies that you either need to invokesetWrappee(MatsInitiate)
before publishing the instance (making it available for other threads), or overrideunwrap()
to provide the desiredMatsInitiator.MatsInitiate
instance.MatsInitiateWrapper
(MatsInitiator.MatsInitiate targetMatsInitiate) Standard constructor, taking the wrappedMatsInitiator.MatsInitiate
instance. -
Method Summary
Modifier and TypeMethodDescriptionAdds a binary payload to the outgoing request message, e.g.Adds a String payload to the outgoing request message, e.g.Sets the originating/initiating "synthetic endpoint Id" - only used for statistics/tracing/debugging.<T> Optional<T>
getAttribute
(Class<T> type, String... name) Provides a way to get hold of (optional) attributes/objects from the Mats implementation, either specific to the Mats implementation in use, or configured into this instance of the Mats implementation.Prioritize this Mats flow! Hint to the underlying implementation that a human is actually waiting for the result of a request, and that the flow therefore should be prioritized.keepTrace
(MatsInitiator.KeepTrace keepTrace) Hint to the underlying implementation to which level of call and state history the underlying protocol should retain.logMeasurement
(String metricId, String metricDescription, String baseUnit, double measure, String... labelKeyValue) Adds a measurement of a described variable, in a base unit, for this Initiation - be sure to understand that the three String parameters are constants for each measurement. To exemplify, you may measure five different things in an Initiation, i.e.logTimingMeasurement
(String metricId, String metricDescription, long nanos, String... labelKeyValue) Same asaddMeasurement(..)
, but specifically for timings - Read that JavaDoc!noAudit()
Marks this Mats flow as not relevant for auditing.Enable unreliable, but fast, messaging! Hint to the underlying implementation that it does not matter that much if this message is lost.nonPersistent
(long timeToLiveMillis) Same asMatsInitiator.MatsInitiate.nonPersistent()
, but you can set a time-to-live too.Sends a message to aSubscriptionTerminator
, employing the publish/subscribe pattern instead of message queues (topic in JMS terms).Variation of theMatsInitiator.MatsInitiate.publish(Object)
method, where the incoming state is sent along.Specified which MATS Endpoint the reply of the invoked Endpoint should go to.replyToSubscription
(String endpointId, Object replySto) A "pub-sub" variant ofreplyTo
, where the reply will go to the specified endpointId which must be aSubscriptionTerminator
.The standard request initiation method: All of from, to and replyTo must be set.Variation of the request initiation method, where the incoming state is sent along.Sends a message to an endpoint, without expecting any reply ("fire-and-forget").Variation of theMatsInitiator.MatsInitiate.send(Object)
method, where the incoming state is sent along.setTraceProperty
(String propertyName, Object propertyValue) Adds a property that will "stick" with the call flow from this call on out.void
setWrappee
(MatsInitiator.MatsInitiate targetMatsInitiate) Sets the wrappedMatsInitiator.MatsInitiate
, e.g.Sets which MATS Endpoint this message should go.toString()
traceId
(CharSequence traceId) Sets (or appends with a joining "|" in case ofinitiation within a stage
) the supplied Trace Id, which is solely used for logging and debugging purposes.<R,
S, I> void unstash
(byte[] stash, Class<R> replyClass, Class<S> stateClass, Class<I> incomingClass, MatsEndpoint.ProcessLambda<R, S, I> lambda) Unstashes a Mats Flow that have been previouslystashed
.unwrap()
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait
Methods inherited from interface io.mats3.MatsFactory.MatsWrapper
unwrapTo
-
Constructor Details
-
MatsInitiateWrapper
Standard constructor, taking the wrappedMatsInitiator.MatsInitiate
instance.- Parameters:
targetMatsInitiate
- theMatsFactory
instance whichunwrap()
will return (and hence all forwarded methods will use).
-
MatsInitiateWrapper
public MatsInitiateWrapper()No-args constructor, which implies that you either need to invokesetWrappee(MatsInitiate)
before publishing the instance (making it available for other threads), or overrideunwrap()
to provide the desiredMatsInitiator.MatsInitiate
instance. In these cases, make sure to honor memory visibility semantics - i.e. establish a happens-before edge between the setting of the instance and any other threads getting it.
-
-
Method Details
-
setWrappee
Sets the wrappedMatsInitiator.MatsInitiate
, e.g. in case you instantiated it with the no-args constructor. Do note that the field holding the wrapped instance is not volatile nor synchronized. This means that if you want to set it after it has been published to other threads, you will have to override both this method andunwrap()
to provide for needed memory visibility semantics, i.e. establish a happens-before edge between the setting of the instance and any other threads getting it. Avolatile
field would work nice.- Specified by:
setWrappee
in interfaceMatsFactory.MatsWrapper<MatsInitiator.MatsInitiate>
- Parameters:
targetMatsInitiate
- theMatsInitiator.MatsInitiate
which is returned byunwrap()
, unless that is overridden.
-
unwrap
- Specified by:
unwrap
in interfaceMatsFactory.MatsWrapper<MatsInitiator.MatsInitiate>
- Returns:
- the wrapped
MatsInitiator.MatsInitiate
. All forwarding methods invokes this method to get the wrappedMatsInitiator.MatsInitiate
, thus if you want to get creative wrt. how and when the MatsInitiate is decided, you can override this method.
-
unwrapFully
- Specified by:
unwrapFully
in interfaceMatsFactory.MatsWrapper<MatsInitiator.MatsInitiate>
- Specified by:
unwrapFully
in interfaceMatsInitiator.MatsInitiate
- Returns:
- the fully unwrapped instance: If the returned instance from
MatsFactory.MatsWrapper.unwrap()
is itself aMatsWrapper
, it will recurse down by invoking this method (unwrapFully()
) again on the returned target.
-
traceId
Description copied from interface:MatsInitiator.MatsInitiate
Sets (or appends with a joining "|" in case ofinitiation within a stage
) the supplied Trace Id, which is solely used for logging and debugging purposes. It should be unique, at least to a degree where it is very unlikely that you will have two identical traceIds within a couple of years ("guaranteed globally unique through all time" is not relevant). Since this is very important when doing distributed and asynchronous architectures, it is mandatory. The traceId follows a Mats processing from the initiation until it is finished, usually in a Terminator. It should be a world-unique Id, preferably set all the way back when some actual person performed some event. E.g. in a "new order" situation, the Id would best be set when the user clicked the "place order" button on the web page - or maybe even derived from the event when he first initiated the shopping cart - or maybe even when he started the session. The point is that when using e.g. Kibana or Splunk to track events that led to some outcome, a robust, versatile and information-rich track/trace Id makes wonders. It is strongly recommended to use small, dense, information rich Trace Ids. Sticking in an UUID as Trace Id certainly fulfils the uniqueness-requirement, but it is a crappy solution, as it by itself does not give any hint of source, cause, relevant entities, or goal. (It isn't even dense for the uniqueness an UUID gives, which also is way above the required uniqueness unless you handle billions of such messages per minute. A random alphanum (A-Z,a-z,0-9) string of much smaller length would give plenty enough uniqueness). The following would be a much better Trace Id than a random UUID, which follows some scheme that could be system wide: "Web.placeOrder[cid:43512][cart:xa4ru5285fej]qz7apy9". From this example TraceId we could infer that it originated at the Web system, it regards Placing an order for Customer Id 43512, it regards the Shopping Cart Id xa4ru5285fej, and it contains some uniqueness ('qz7apy9') generated at the initiating, so that even if the customer managed to click three times on the "place order" button for the same cart, you would still be able to separate the resulting three different Mats call flows. You should consider storing the traceId as a column in any inserted rows in any databases that was affected by this call flow, e.g. in the row for a placed order, you'd have the traceId as a column. This both to be able to tie this db row back to the logging system, but also if new Mats flows are initiated based on this row, you can include the order TraceId in the new TraceId (with either "|" or "+" as separator). For situations where one Mats Flow "forks" new Mats flows, make new TraceIds for the "sub flows" by tying together the existing TraceId and a new Sub TraceId with a "|". In the order/shipping example, the user would first have placed an order, resulting in an entry in an order database table - where the traceId was stored along. Then, when some batch process Mats Flow initiated the filling process, you would pick up the order's traceId and append that to the sub Mats Flow. Sub Flow Mats TraceId = "{Filling Batch Id}|{Existing Order TraceId}". If you took this all the way, you could in your logging system follow the "total flow" from the initial click on the web page, through the order book, order processing, shipment, and all the way to the delivered and signed package on the person's door - even if the entirety of the order fulfillment consists of multiple "stop and go" sub-flows (the stops being where the process stays for a while as an entry in a database, here "order", then possibly "filling", "shipping" and finally "delivery", or whatever your multiple processes' flows consists of). The "+" character should be used to indicate that an "initiated from the outside" TraceId is concatenated by multiple parts, which so far has been used to pick up an X-Request-ID header from a HTTP-request, and prepending this to the TraceId for a resulting Mats-flow, i.e. Mats TraceId="{X-Request-ID}+{Flow TraceID}". (Check outMatsFactory.FactoryConfig.setInitiateTraceIdModifier(Function)
for a way to automate this.) The difference between "|" and "+" is meant to be that "|" indicates that there is a Mats Flow TraceId on both sides of the "|", while the "+" is used when a "from the outside"-initiated TraceId is built up by multiple pieces, e.g. X-Request-Id, or Batch Run Number, on the left side. Remember, this is all meant for human consumption, in particular when debugging. Do what you feel is meaningful - the Mats system doesn't care! (For the default implementation "JMS Mats", the Trace Id is set on theMDC
of the SLF4J logging system, using the key "traceId". Since this implementation logs a few lines per handled message, in addition to any log lines you emit yourself, you will, by collecting the log lines in a common log system (e.g. the ELK stack), be able to very easily follow the processing trace through all the services the call flow passes.)- Specified by:
traceId
in interfaceMatsInitiator.MatsInitiate
- Parameters:
traceId
- the traceId that will follow the mats trace from initiation (first call) to termination (last call, where the flow ends). Although the type isCharSequence
, the implementation will immediately dotoString()
on the instance to fix the value.- Returns:
- the
MatsInitiator.MatsInitiate
for chaining.
-
keepTrace
Description copied from interface:MatsInitiator.MatsInitiate
Hint to the underlying implementation to which level of call and state history the underlying protocol should retain. The default (unless configured otherwise),MatsInitiator.KeepTrace.COMPACT
, keeps a trail of all the stages the flow has been through, but drops state and DTOs that aren't relevant for the current message. You might want to useMatsInitiator.KeepTrace.FULL
while developing new functionality, while once a certain call flow stabilizes, without much errors or DLQs, you should consider initializing it withMatsInitiator.KeepTrace.COMPACT
or evenMatsInitiator.KeepTrace.MINIMAL
(the latter also dropping the "trail", thus only keeping information strictly relevant for the current message). This functionality is solely for debugging, the Mats endpoints works identically with any setting, thus it is a tradeoff between performance (size of messages) and debuggability. The resulting kept trace would typically be visible in a "toString()" of theMatsEndpoint.ProcessContext
- or in an external (e.g. Brokerside) debugging/tracing system.- Specified by:
keepTrace
in interfaceMatsInitiator.MatsInitiate
- Returns:
- the
MatsInitiator.MatsInitiate
for chaining.
-
nonPersistent
Description copied from interface:MatsInitiator.MatsInitiate
Enable unreliable, but fast, messaging! Hint to the underlying implementation that it does not matter that much if this message is lost. The implication is that the messages that this flow consist of are unreliable - typically, if the MQ broker is restarted, any outstanding "non persistent" messages are lost. (Also, some backends will (in default config) lose the Dead Letter Queue (DLQ) functionality when this is used, where a ordinary persistent message would be DLQed if it failed to be delivered to an endpoint. This can severely impact monitoring (as you don't get a build-up of DLQs when things goes wrong - only log lines) and to a degree debugging (since you don't have the DLQ'ed messages to look at).) This is only usable for "pure GET"-style requests without any state changes along the flow, i.e. "AccountService.getBalances", for display to an end user. If such a message is lost, the world won't go under. The upshot here is that non-persistent messaging typically is blazingly fast and is way less resource demanding, as the messages will not have to (transactionally) be stored in non-volatile storage. It is therefore wise to actually employ this feature where it makes sense (which, again, is only relevant for side-effect free GET-style requests).- Specified by:
nonPersistent
in interfaceMatsInitiator.MatsInitiate
- Returns:
- the
MatsInitiator.MatsInitiate
for chaining.
-
nonPersistent
Description copied from interface:MatsInitiator.MatsInitiate
Same asMatsInitiator.MatsInitiate.nonPersistent()
, but you can set a time-to-live too. If the message gets this old and have not yet been delivered to the receiving Mats endpoint, it will be deleted and never delivered. This functionality often makes sense for messages that are bothinteractive
andnon-persistent
: Such messages shall only be "getters" free of any side effects (i.e. no state is changed by the entire message flow), and where a human is actively waiting for the reply. If there is a situation where such messages aren't consumed due to the receiving service having problems, it does not make sense to use processing resources to handle a massive stack of these messages when the consumption is restored an hour later, as e.g. the synchronously waiting HTTP call that was waiting for the reply has timed out, and the waiting human is probably long gone anyway. Notice on use: This should NOT be employed for message flows where any stage might change any state, i.e. message flows with side effects (Think "PUT", "POST" and "DELETE"-style messages) - which also should NOT employnon-persistent
messaging. The rationale is that such messages should never just cease to exists, for any reason - they should have both guaranteed delivery and execution. You should also never use this to handle any business logic, e.g. some kind of order time-out where an order is only valid until 21:00, or something like this. This both because of the "Note on implementation" below, and that the entire facility of "time to live" is optional both for Mats and for the underlying message queue system. Notice on implementation: If the message is a part of a multi-message flow, which most Mats initiations pretty much invariably is (a request consists of a request-message and a reply-message), this TTL will be set afresh on every new message in the flow, possibly with the amount of time taken in the processing of the stage deducted. However, the time that the message waited in queue will not be deducted. The effective TTL of the flow might therefore be a multiple of what is set here. An example: The TTL of an initiation is set to 5000 ms. The request message stays 4 seconds in queue, before being received and processed, where the processing took 100 ms. The reply-message will thus have its TTL set to 4900 ms: 5000 ms TTL - 100 ms for processing. The reply message stays 4 seconds in queue before being received. The total "time in flight" has now been 8.1 seconds, and there was still 900 ms left of the reply-message's TTL. The rationale for not deducting queue-time on the subsequent message is that there is no easy way to get the "queue time" which does not involve taking the difference between two timestamps, but in a multi-server architecture there is a clear possibility of clock skews between different services, even for instances of the same service. You could then deduce a too high queue time, deducting a too high value from the reply-message's TTL, and effectively time out the full message flow too early. However, for the intended use case - to hinder build-up of messages that will nevertheless be valueless when the answer is received since the interactively waiting human is long gone - this is no big problem.- Specified by:
nonPersistent
in interfaceMatsInitiator.MatsInitiate
- Parameters:
timeToLiveMillis
- the number of milliseconds before this message is timed out and thus will never be delivered - 0 means "live forever", and this is the default.- Returns:
- the
MatsInitiator.MatsInitiate
for chaining.
-
interactive
Description copied from interface:MatsInitiator.MatsInitiate
Prioritize this Mats flow! Hint to the underlying implementation that a human is actually waiting for the result of a request, and that the flow therefore should be prioritized. This status will be kept through the entire flow, so that all messages in the flow are prioritized. This makes it possible to use the same "AccountService.getBalances" service both for the Web Application that the user facing GUI are employing, and the batch processing of a ton of orders. Without such a feature, the interactive usage could be backlogged by the batch process, while if the interactive flag is set, it will bypass the backlog of "ordinary" messages. This implies that MATS defines two levels of prioritization: "Ordinary" and "Interactive". Most processing should employ the default, i.e. "Ordinary", while places where a human is actually waiting for the reply should employ the fast-lane, i.e. "Interactive". It is imperative to not abuse this feature, or else it will loose its value: If batches are going too slow, nothing will be gained by setting the interactive flag except destroying the entire point of this feature. Instead use higher parallelism: By increasingconcurrency
or the number of nodes that is running the problematic endpoint or stage; increase the speed and/or throughput of external systems like the database; or somehow just code the whole thing to be faster! It will often make sense to set both this flag, and theMatsInitiator.MatsInitiate.nonPersistent()
, at the same time. E.g. when you need to show the account balance for a customer: It both needs to skip past any bulk/batch queue of such requests (since a human is literally waiting for the result), but it is also a "pure GET"-style request, not altering state whatsoever, so it can also be set to non-persistent.- Specified by:
interactive
in interfaceMatsInitiator.MatsInitiate
- Returns:
- the
MatsInitiator.MatsInitiate
for chaining.
-
noAudit
Description copied from interface:MatsInitiator.MatsInitiate
Marks this Mats flow as not relevant for auditing. When considering auditing ("event sourcing"-style) of all messages, one quickly realizes that there are very many messages that aren't that interesting to log. These are pure getters employed to show information to users, and even worse in this respect, "Are you up?"-type health checks. This flag is here to mark messages as such: "You will gain no historic insight in logging the following message flow!". This flag should NOT be set for ANY messages that (can potentially) change state in any part of the total system (i.e. "permanent state", e.g. a row in a database). More subtle, the flag should also not be set for "getters" that are performed to decide upon a state - e.g. for validation of new orders: The getter that checks credit should be audited. If such a getter is a part of a Mats flow, this should not be a problem, as the initiator of the "add order" Mats flow would obviously not set noAudit(). However, if it is coded as multiple "stop and go" flows, i.e. add the order to some incoming order table. Then a next, separate Mats flow is validation: That getter should be audited, hence do not set noAudit(). Note: It might be interesting to log that such messages actually happened, but not the content of them. This is to be able to tally them, i.e. "WebService.healthCheck is invoking AccountService.webStatus 52389052 times per day" - both to see that it is probably a bit excessive, and to see that there is traffic there at all (since AccountService.webStatus seems to be a pretty specific endpoint). However, there is probably not much use in storing the contents of such calls - and maybe not retain the calls for more than a few months.- Specified by:
noAudit
in interfaceMatsInitiator.MatsInitiate
- Returns:
- the
MatsInitiator.MatsInitiate
for chaining.
-
from
Description copied from interface:MatsInitiator.MatsInitiate
Sets the originating/initiating "synthetic endpoint Id" - only used for statistics/tracing/debugging. If this message is initiated from within a stage, i.e. by use ofMatsEndpoint.ProcessContext.initiate(InitiateLambda)
, the 'from' property is already set to the stageId of the currently processing Stage, but it can be overridden if desired. It is important that you do not make this into a dynamic string, i.e. do not add some Id to it (such Ids should go into the traceId). It it is smart to decide on a common prefix for all Mats Endpoints and InitiatorIds for a particular service. E.g. "OrderService" or "InventoryService" or something like this. A good value that would be of use when debugging a call trace is something following a structure like"OrderService.REST.place_order_from_user"
, this example trying to convey that it is from the OrderSystem, coming in over its REST endpoint "place_order_from_user". Note that there are no e.g. userId there. NOTE: This is only used for tracing/debugging (in particular, it is not related to thereplyTo
functionality), but should be set to something that will give insights when you try to make sense of call flows. Think of a introspection system showing a histogram of where messages are initiated, so that you can see that 45% of the messages are coming from the OrderSystem's REST endpoints, and 15% of all initiations are its "place_order_from_user". This also implies that it shall not be a dynamic value, i.e. do not put something that will vary between each call, that is, do NOT add the user's Id or something like that. Such dynamic elements is what theMatsInitiator.MatsInitiate.traceId(CharSequence)
is for.- Specified by:
from
in interfaceMatsInitiator.MatsInitiate
- Parameters:
initiatorId
- the originating/initiating "synthetic endpoint Id" - only used for tracing/debugging.- Returns:
- the
MatsInitiator.MatsInitiate
for chaining.
-
to
Description copied from interface:MatsInitiator.MatsInitiate
Sets which MATS Endpoint this message should go.- Specified by:
to
in interfaceMatsInitiator.MatsInitiate
- Parameters:
endpointId
- to which MATS Endpoint this message should go.- Returns:
- the
MatsInitiator.MatsInitiate
for chaining.
-
replyTo
Description copied from interface:MatsInitiator.MatsInitiate
Specified which MATS Endpoint the reply of the invoked Endpoint should go to.- Specified by:
replyTo
in interfaceMatsInitiator.MatsInitiate
- Parameters:
endpointId
- which MATS Endpoint the reply of the invoked Endpoint should go to.replySto
- the object that should be provided as STO to the service which get the reply.- Returns:
- the
MatsInitiator.MatsInitiate
for chaining.
-
replyToSubscription
Description copied from interface:MatsInitiator.MatsInitiate
A "pub-sub" variant ofreplyTo
, where the reply will go to the specified endpointId which must be aSubscriptionTerminator
.- Specified by:
replyToSubscription
in interfaceMatsInitiator.MatsInitiate
- Parameters:
endpointId
- which MATS Endpoint the reply of the invoked Endpoint should go to.replySto
- the object that should be provided as STO to the service which get the reply.- Returns:
- the
MatsInitiator.MatsInitiate
for chaining.
-
setTraceProperty
Description copied from interface:MatsInitiator.MatsInitiate
Adds a property that will "stick" with the call flow from this call on out. Read more onMatsEndpoint.ProcessContext.setTraceProperty(String, Object)
.- Specified by:
setTraceProperty
in interfaceMatsInitiator.MatsInitiate
- Parameters:
propertyName
- the name of the propertypropertyValue
- the value of the property, which will be serialized using the active MATS serializer.- See Also:
-
logMeasurement
public MatsInitiator.MatsInitiate logMeasurement(String metricId, String metricDescription, String baseUnit, double measure, String... labelKeyValue) Description copied from interface:MatsInitiator.MatsInitiate
Adds a measurement of a described variable, in a base unit, for this Initiation - be sure to understand that the three String parameters are constants for each measurement. To exemplify, you may measure five different things in an Initiation, i.e. "number of items in order", "total amount for order in dollar", etc - and each of these obviously have different metricId, metricDescription and possibly different baseUnit from each other. BUT, the specific arguments for "number of items in order" (outside the measure itself!) shall not change between one Initiation and the next (of the same "type", i.e. place in the code): e.g. the metricDescription shall NOT be dynamically constructed to e.g. say "Number of items in order 1234 for customer 5678". Note: It is illegal to use the same 'metricId' for more than one measurement for a given Initiation, and this also goes between measurements andtiming measurements
. Inclusion as metric by plugin 'mats-intercept-micrometer': A new meter will be created (and cached), of typeDistributionSummary
, with the 'name' set to"mats.exec.ops.measure.{metricId}.{baseUnit}"
("measure"->"time" for timings), and 'description' to description. (Tags/labels already added on the meter by the plugin include 'appName', 'initiatorId', 'initiatingAppName', 'stageId' (for stages), and 'initiatorName' (for inits)). Read about parameter 'labelKeyValue' below. Inclusion as log line by plugin 'mats-intercept-logging': A log line will be output by each added measurement, where the MDC for that log line will have an entry with key"mats.ops.measure.{metricId}.{baseUnit}"
. Read about parameter 'labelKeyValue' below. It generally makes most sense if the same metrics are added for each processing of a particular Initiation, i.e. if the "number of items" are 0, then that should also be recorded along with the "total amount for order in dollar" as 0, not just elided. Otherwise, your metrics will be skewed. You should use a dot-notation for the metricId if you want to add multiple meters with a hierarchical/subdivision layout. The vararg 'labelKeyValue' is an optional element where the String-array consist of one or several alternate key, value pairs. Do not employ this feature unless you know what the effects are, and you actually need it! This will be added as labels/tags to the metric, and added to the SLF4J MDC for the measurement log line with the key being"mats.ops.measure.{metricId}.{labelKey}"
("measure"->"time" for timings). The keys should be constants as explained for the other parameters, while the value can change, but only between a given set of values (thinkenum
) - using e.g. the 'customerId' as value doesn't make sense and will blow up your metric cardinality. Notice that if you do employ e.g. two labels, each having one of three values, you'll effectively create 9 different meters, where your measurement will go to one of them. NOTICE: If you want to do a timing, then instead useMatsInitiator.MatsInitiate.logTimingMeasurement(String, String, long, String...)
- Specified by:
logMeasurement
in interfaceMatsInitiator.MatsInitiate
- Parameters:
metricId
- constant, short, possibly dot-separated if hierarchical, id for this particular metric, e.g. "items" or "amount", or "db.query.orders".metricDescription
- constant, textual description for this metric, e.g. "Number of items in customer order", "Total amount of customer order"baseUnit
- the unit for this measurement, e.g. "quantity" (for a count measure), "dollar" (for an amount), or "bytes" (for a document size).measure
- value of the measurementlabelKeyValue
- a String-vararg array consisting of alternate key,value pairs which will becomes labels or tags or entries for the metrics and log lines. Read the JavaDoc above; the keys shall be "static" for a specific measure, while the values can change between a specific small set values.- Returns:
- the
MatsInitiator.MatsInitiate
for chaining.
-
logTimingMeasurement
public MatsInitiator.MatsInitiate logTimingMeasurement(String metricId, String metricDescription, long nanos, String... labelKeyValue) Description copied from interface:MatsInitiator.MatsInitiate
Same asaddMeasurement(..)
, but specifically for timings - Read that JavaDoc! Note: It is illegal to use the same 'metricId' for more than one measurement for a given Initiation, and this also goes between timing measurements andmeasurements
. For the metrics-plugin 'mats-intercept-micrometer' plugin, the 'baseUnit' argument is deduced to whatever is appropriate for the receiving metrics system, e.g. for Prometheus it is "seconds", even though you always record the measurement in nanoseconds using this method. For the logging-plugin 'mats-intercept-logging' plugin, the timing in the log line will be in milliseconds (with fractions), even though you always record the measurement in nanoseconds using this method.- Specified by:
logTimingMeasurement
in interfaceMatsInitiator.MatsInitiate
- Parameters:
metricId
- constant, short, possibly dot-separated if hierarchical, id for this particular metric, e.g. "db.query.orders" or "calcprofit".metricDescription
- constant, textual description for this metric, e.g. "Time taken to execute order query", "Time taken to calculate profit or loss".nanos
- time taken in nanosecondslabelKeyValue
- a String-vararg array consisting of alternate key,value pairs which will becomes labels or tags or entries for the metrics and log lines. Read the JavaDoc ataddMeasurement(..)
- Returns:
- the
MatsInitiator.MatsInitiate
for chaining.
-
addBytes
Description copied from interface:MatsInitiator.MatsInitiate
Adds a binary payload to the outgoing request message, e.g. a PDF document. The rationale for having this is to not have to encode a largish byte array inside the JSON structure that carries the Request DTO - byte arrays represent very badly in JSON. Note: The byte array is not compressed (as might happen with the DTO), so if the payload is large, you might want to consider compressing it before attaching it (and will then have to decompress it on the receiving side).- Specified by:
addBytes
in interfaceMatsInitiator.MatsInitiate
- Parameters:
key
- the key on which to store the byte array payload. The receiver will have to use this key to get the payload out again, so either it will be a specific key that the sender and receiver agree upon, or you could generate a random key, and reference this key as a field in the Request DTO.payload
- the byte array.- Returns:
- the
MatsInitiator.MatsInitiate
for chaining. - See Also:
-
addString
Description copied from interface:MatsInitiator.MatsInitiate
Adds a String payload to the outgoing request message, e.g. a XML, JSON or CSV document. The rationale for having this is to not have to encode a largish string document inside the JSON structure that carries the Request DTO. Note: The String payload is not compressed (as might happen with the DTO), so if the payload is large, you might want to consider compressing it before attaching it and instead use theaddBytes(..)
method (and will then have to decompress it on the receiving side).- Specified by:
addString
in interfaceMatsInitiator.MatsInitiate
- Parameters:
key
- the key on which to store the String payload. The receiver will have to use this key to get the payload out again, so either it will be a specific key that the sender and receiver agree upon, or you could generate a random key, and reference this key as a field in the Request DTO.payload
- the string.- Returns:
- the
MatsInitiator.MatsInitiate
for chaining. - See Also:
-
request
Description copied from interface:MatsInitiator.MatsInitiate
The standard request initiation method: All of from, to and replyTo must be set. A message is sent to a service, and the reply from that service will come to the specified reply endpointId, typically a terminator.- Specified by:
request
in interfaceMatsInitiator.MatsInitiate
- Parameters:
requestDto
- the object which the endpoint will get as its incoming DTO (Data Transfer Object).
-
request
Description copied from interface:MatsInitiator.MatsInitiate
Variation of the request initiation method, where the incoming state is sent along. This only makes sense if the same code base "owns" both the initiation code and the endpoint to which this message is sent. It is mostly here for completeness, since it is possible to send state along with the message, but if employed between different services, it violates the premise that MATS is built on: State is private to the stages of a multi-stage endpoint, and the Request and Reply DTOs are the public interface.- Specified by:
request
in interfaceMatsInitiator.MatsInitiate
- Parameters:
requestDto
- the object which the target endpoint will get as its incoming DTO (Data Transfer Object).initialTargetSto
- the object which the target endpoint will get as its STO (State Transfer Object).
-
send
Description copied from interface:MatsInitiator.MatsInitiate
Sends a message to an endpoint, without expecting any reply ("fire-and-forget"). The 'reply' parameter must not be set. Note that the difference betweenrequest(..)
andsend(..)
is only that replyTo is not set for send, otherwise the mechanism is exactly the same.- Specified by:
send
in interfaceMatsInitiator.MatsInitiate
- Parameters:
messageDto
- the object which the target endpoint will get as its incoming DTO (Data Transfer Object).
-
send
Description copied from interface:MatsInitiator.MatsInitiate
Variation of theMatsInitiator.MatsInitiate.send(Object)
method, where the incoming state is sent along. This only makes sense if the same code base "owns" both the initiation code and the endpoint to which this message is sent. It is mostly here for completeness, since it is possible to send state along with the message, but if employed between different services, it violates the premise that MATS is built on: State is private to the stages of a multi-stage endpoint, and the Request and Reply DTOs are the public interface.- Specified by:
send
in interfaceMatsInitiator.MatsInitiate
- Parameters:
messageDto
- the object which the target endpoint will get as its incoming DTO (Data Transfer Object).initialTargetSto
- the object which the target endpoint will get as its STO (State Transfer Object).
-
publish
Description copied from interface:MatsInitiator.MatsInitiate
Sends a message to aSubscriptionTerminator
, employing the publish/subscribe pattern instead of message queues (topic in JMS terms). This means that all of the live servers that are listening to this endpointId will receive the message, and if there are no live servers, then no one will receive it. The concurrency of a SubscriptionTerminator is always 1, as it only makes sense for there being only one receiver per server - otherwise it would just mean that all of the active listeners on one server would get the message, per semantics of the pub/sub. It is only possible to publish to SubscriptionTerminators as employing publish/subscribe for multi-stage services makes no sense.- Specified by:
publish
in interfaceMatsInitiator.MatsInitiate
- Parameters:
messageDto
- the object which the target endpoint will get as its incoming DTO (Data Transfer Object).
-
publish
Description copied from interface:MatsInitiator.MatsInitiate
Variation of theMatsInitiator.MatsInitiate.publish(Object)
method, where the incoming state is sent along. This only makes sense if the same code base "owns" both the initiation code and the endpoint to which this message is sent. The possibility to send state along with the request makes most sense with the publish method: A SubscriptionTerminator is often paired with a Terminator, where the Terminator receives the message, typically a reply from a requested service, along with the state that was sent in the initiation. The terminator does any "needs to be guaranteed to be performed" state changes to e.g. database, and then passes the incoming message - along with the same state it received - on to a SubscriptionTerminator. The SubscriptionTerminator performs any updates of any connected GUI clients, or for any other local states, e.g. invalidation of caches, on all live servers listening to that endpoint, the point being that if no servers are live at that moment, no one will process that message - but at the same time, there is obviously no GUI clients connected, nor are there are local state in form of caches that needs to be invalidated.- Specified by:
publish
in interfaceMatsInitiator.MatsInitiate
- Parameters:
messageDto
- the object which the target endpoint will get as its incoming DTO (Data Transfer Object).initialTargetSto
- the object which the target endpoint will get as its STO (State Transfer Object).
-
unstash
public <R,S, void unstashI> (byte[] stash, Class<R> replyClass, Class<S> stateClass, Class<I> incomingClass, MatsEndpoint.ProcessLambda<R, S, I> lambda) Description copied from interface:MatsInitiator.MatsInitiate
Unstashes a Mats Flow that have been previouslystashed
. To be able to deserialize the stashed bytes to instances provided to the suppliedMatsEndpoint.ProcessLambda
, you need to provide the classes of the original stage's Reply, State and Incoming objects.- Specified by:
unstash
in interfaceMatsInitiator.MatsInitiate
- Type Parameters:
R
- type of the ReplyClassS
- type of the StateClassI
- type of the IncomingClass- Parameters:
stash
- the stashed bytes which now should be unstashedreplyClass
- the class which the original stage originally would reply with.stateClass
- the class which used for state in the original stage (endpoint) - orVoid.TYPE
(i.e.void.class
) if none.incomingClass
- the class which the original stage gets as incoming DTO.lambda
- the stage lambda which should now be executed instead of the original stage lambda where stash was invoked.
-
getAttribute
Description copied from interface:MatsInitiator.MatsInitiate
Provides a way to get hold of (optional) attributes/objects from the Mats implementation, either specific to the Mats implementation in use, or configured into this instance of the Mats implementation. Mirrors the same method atMatsEndpoint.ProcessContext.getAttribute(Class, String...)
. There is also a ThreadLocal-accessible version atMatsFactory.ContextLocal.getAttribute(Class, String...)
. Mandatory: If the Mats implementation has a transactional SQL Connection, it shall be available by'context.getAttribute(Connection.class)'
.- Specified by:
getAttribute
in interfaceMatsInitiator.MatsInitiate
- Type Parameters:
T
- The type of the attribute.- Parameters:
type
- The expected type of the attributename
- The (optional) (hierarchical) name(s) of the attribute.- Returns:
- Optional of the attribute in question, the optionality pointing out that it depends on the Mats implementation or configuration whether it is available.
- See Also:
-
toString
-