diff --git a/semantic_conventions/trace/job.yaml b/semantic_conventions/trace/job.yaml new file mode 100644 index 00000000000..eabca98e5f6 --- /dev/null +++ b/semantic_conventions/trace/job.yaml @@ -0,0 +1,158 @@ +groups: + - id: job + prefix: job + brief: > + This document defines the attributes used in + batch job queuing and processing systems. + attributes: + - id: system + required: always + brief: > + A string identifying the job processing system. + type: + allow_custom_values: true + members: + - id: active_job + value: 'active_job' + brief: 'Active Job' + - id: airflow + value: 'airflow' + brief: 'Apache Airflow' + - id: celery + value: 'celery' + brief: 'Oracle Database' + - id: delayed_job + value: 'delayed_job' + brief: 'Delayed Job' + - id: exq + value: 'exq' + brief: 'Exq' + - id: faktory + value: 'faktory' + brief: 'Faktory' + - id: hangfire + value: 'hangfire' + brief: 'Hangfire' + - id: minion + value: 'minion' + brief: 'Minion' + - id: oban + value: 'oban' + brief: 'Oban' + - id: rake + value: 'rake' + brief: 'Rake' + - id: resque + value: 'resque' + brief: 'Resque' + - id: sidekiq + value: 'sidekiq' + brief: 'Sidekiq' + - id: spring_batch + value: 'spring_batch' + brief: 'Spring Batch' + - id: sque + value: 'sque' + brief: 'Sque' + - id: toniq + value: 'toniq' + brief: 'Toniq' + - id: workerholic + value: 'workerholic' + brief: 'Workerholic' + - id: name + type: string + required: always + brief: > + The type or class name of the job. + examples: ['SignupMailJob', 'ChargePaymentJob'] + - id: id + type: string + required: always + brief: > + An identifier for the job, represented as a string. + This is typically the database ID of the persisted job object, + which is picked up and worked by a worker process. + Alternatively, it might be an ID of a job run, for example the + job name plus the a timestamp of the run. + examples: 'b18fc2c2f887f61452a7c7c7c7048572' + - id: display_name + type: string + brief: > + A value assigned as a human-readable label for the job. + examples: 'charge-payment-124293' + - id: trigger + type: + allow_custom_values: false + members: + - id: queue + value: 'queue' + brief: 'The job is enqueued for invocation, usually in a first-in-first-out manner' + - id: timer + value: 'timer' + brief: 'The job is set to run by a regular timer' + - id: other + value: 'other' + brief: 'If none of the others apply' + brief: > + Type of the trigger on which the job is performed. + - id: queue_name + type: string + brief: > + The processing queue to which the job belongs. + examples: ['mailers', 'payments'] + - id: priority + type: int + brief: > + The priority value of the job, as defined by the job processing system. Can be positive or negative. + examples: -5 + - id: attempt + type: int + brief: > + The zero-based number previous run attempts which have occurred prior to the current run. + examples: 0 + - id: max_attempts + type: int + brief: > + The maximum number of successive failed run attempts after which the job will be abandoned. + examples: 3 + - id: scheduled_run_time + type: string + brief: > + A string containing the time when the job was scheduled to run, specified in + [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) + format expressed in [UTC](https://www.w3.org/TR/NOTE-datetime). + For job attempts which are being retried, this should reflect when the current + attempt was scheduled (e.g. using a back-off timer.) + examples: "2021-03-23T13:47:06Z" + - ref: net.peer.name + note: > + This should be the IP/hostname of the process (or other network-level peer) used to enqueue or perform job. + required: + conditional: If available. + - ref: net.peer.ip + tag: connection-level + required: + conditional: If available. + constraints: + - include: network + + - id: job.producer + prefix: messaging + extends: messaging + span_kind: producer + brief: > + Semantic convention for producers of jobs. + + - id: job.consumer + prefix: messaging + extends: messaging + span_kind: consumer + brief: > + Semantic convention for a consumer of jobs + attributes: + - id: pool + type: string + brief: > + The name or identifier of the worker pool used to run the job. + examples: ['mailers', 'payments'] diff --git a/specification/trace/semantic_conventions/job.md b/specification/trace/semantic_conventions/job.md new file mode 100644 index 00000000000..00c17bfcc1d --- /dev/null +++ b/specification/trace/semantic_conventions/job.md @@ -0,0 +1,379 @@ +# Messaging systems + +**Status**: [Experimental](../../document-status.md) + + + + + +- [Definitions](#definitions) + * [Destinations](#destinations) + * [Message consumption](#message-consumption) + * [Conversations](#conversations) + * [Temporary destinations](#temporary-destinations) +- [Conventions](#conventions) + * [Span name](#span-name) + * [Span kind](#span-kind) + * [Operation names](#operation-names) +- [Messaging attributes](#messaging-attributes) + * [Attributes specific to certain messaging systems](#attributes-specific-to-certain-messaging-systems) + + [RabbitMQ](#rabbitmq) + + [Apache Kafka](#apache-kafka) +- [Examples](#examples) + * [Topic with multiple consumers](#topic-with-multiple-consumers) + * [Apache Kafka Example](#apache-kafka-example) + * [Batch receiving](#batch-receiving) + * [Batch processing](#batch-processing) + + + +## Definitions + +Although job systems are not as standardized as, e.g., HTTP, it is assumed that the following definitions are applicable to most of them that have similar concepts at all: + +A *job* is an envelope with a potentially empty payload. +This envelope may offer the possibility to convey additional metadata, often in key/value form. + +A job is sent by a message *consumer* (also referred to as a worker in some contexts) to: + +* Physically: some message *broker* (which can be e.g., a single server, or a cluster, or a local process reached via IPC). The broker handles the actual delivery, re-delivery, persistence, etc. In some messaging systems the broker may be identical or co-located with (some) message consumers. +With Apache Kafka, the physical broker a message is written to depends on the number of partitions, and which broker is the *leader* of the partition the record is written to. +* Logically: some particular message *destination*. + +Messages can be delivered to 0, 1, or multiple consumers depending on the dispatching semantic of the protocol. + + + + + + + + +==================== + +This PR defines a semantic convention for "Job" traces. + +A "Job" models a batch job or task, which can be either enqueued, scheduled, or run on-demand. + +Examples of job-related systems are: + +Sidekiq, instrumented here using "Messaging" convention +Delayed Job, instrumented here using "Messaging" convention +Celery, instrumented here using "Messaging" convention +Resque, issue here +Rake, issue here +Apache Airflow, issue here +The spec for "Job" would be somewhere between "Messaging" and "FAAS". It would cover both the producer and consumer aspects of running jobs. + +As noted above, OTEL instrumentation libraries are using the "Messaging" convention to represent Jobs today. However "Messaging", which is intended for Kafka, RabbitMQ, etc. is not a great fit: + +Messaging systems focus on the delivery of messages irrespective of the message contents. Jobs performing work/processing based on the job instruction. +In a Messaging system the categorization is done by the "queue" or "topic" on which messages are transmitted; in a trace viewing system (e.g. Datadog, Lightstep, etc.) I would want to see messages labelled according to their queue. In Job systems, the categorization is based on job name/type, and the queue is just for worker (consumer) resource allocation. Hence I would want traces labelled as "ChargePaymentJob", "RefundPaymentJob", etc. even though all such jobs are in the same "payments" queue. +FAAS is also not ideal, as it is typically for serverless providers such as AWS Lambda which the infrastructure running the job has been abstracted away, and the primary focus is on the "function". + + + + + + + + + + + + + + + +### Destinations + +A destination is usually identified by some name unique within the messaging system instance, which might look like a URL or a simple one-word identifier. +Traditional messaging, such as JMS, involves two kinds of destinations: *topic*s and *queue*s. +A message that is sent (the send-operation is often called "*publish*" in this context) to a *topic* is broadcasted to all consumers that have *subscribed* to the topic. +A message submitted to a queue is processed by a message *consumer* (usually exactly once although some message systems support a more performant at-least-once mode for messages with [idempotent][] processing). + +In a messaging system such as Apache Kafka, all destinations are *topic*s. +Each record, or message, is sent to a single consumer per consumer group. +Consumer groups provide *deliver once* semantics for consumers of a topic within a group. +Whether a specific message is processed as if it was sent to a topic or queue entirely depends on the consumer groups and their composition. +For instance, there can be multiple consumer groups processing records from the same topic. + +[idempotent]: https://en.wikipedia.org/wiki/Idempotence + +### Message consumption + +The consumption of a message can happen in multiple steps. +First, the lower-level receiving of a message at a consumer, and then the logical processing of the message. +Often, the waiting for a message is not particularly interesting and hidden away in a framework that only invokes some handler function to process a message once one is received +(in the same way that the listening on a TCP port for an incoming HTTP message is not particularly interesting). + +### Conversations + +In some messaging systems, a message can receive one or more reply messages that answers a particular other message that was sent earlier. All messages that are grouped together by such a reply-relationship are called a *conversation*. +The grouping usually happens through some sort of "In-Reply-To:" meta information or an explicit *conversation ID* (sometimes called *correlation ID*). +Sometimes a conversation can span multiple message destinations (e.g. initiated via a topic, continued on a temporary one-to-one queue). + +### Temporary destinations + +Some messaging systems support the concept of *temporary destination* (often only temporary queues) that are established just for a particular set of communication partners (often one to one) or conversation. +Often such destinations are unnamed or have an auto-generated name. + +## Conventions + +Given these definitions, the remainder of this section describes the semantic conventions for Spans describing interactions with messaging systems. + +### Span name + +The span name SHOULD be set to the message destination name and the operation being performed in the following format: + +``` + +``` + +The destination name SHOULD only be used for the span name if it is known to be of low cardinality (cf. [general span name guidelines](../api.md#span)). +This can be assumed if it is statically derived from application code or configuration. +Wherever possible, the real destination names after resolving logical or aliased names SHOULD be used. +If the destination name is dynamic, such as a [conversation ID](#conversations) or a value obtained from a `Reply-To` header, it SHOULD NOT be used for the span name. +In these cases, an artificial destination name that best expresses the destination, or a generic, static fallback like `"(temporary)"` for [temporary destinations](#temporary-destinations) SHOULD be used instead. + +The values allowed for `` are defined in the section [Operation names](#operation-names) below. +If the format above is used, the operation name MUST match the `messaging.operation` attribute defined for message consumer spans below. + +Examples: + +* `shop.orders send` +* `shop.orders receive` +* `shop.orders process` +* `print_jobs send` +* `topic with spaces process` +* `AuthenticationRequest-Conversations process` +* `(temporary) send` (`(temporary)` being a stable identifier for randomly generated, temporary destination names) + +### Span kind + +A producer of a message should set the span kind to `PRODUCER` unless it synchronously waits for a response: then it should use `CLIENT`. +The processor of the message should set the kind to `CONSUMER`, unless it always sends back a reply that is directed to the producer of the message +(as opposed to e.g., a queue on which the producer happens to listen): then it should use `SERVER`. + +### Operation names + +The following operations related to messages are defined for these semantic conventions: + +| Operation name | Description | +| -------------- | ----------- | +| `send` | A message is sent to a destination by a message producer/client. | +| `receive` | A message is received from a destination by a message consumer/server. | +| `process` | A message that was previously received from a destination is processed by a message consumer/server. | + +## Messaging attributes + + +| Attribute | Type | Description | Examples | Required | +|---|---|---|---|---| +| `job.system` | string | A string identifying the job processing system. | `active_job`; `airflow`; `celery`; `delayed_job` | Yes | +| `job.name` | string | The type or class name of the job. | `SignupMailJob`; `ChargePaymentJob` | Yes | +| `job.id` | string | An identifier for the job, represented as a string. Typically the database ID of the persisted job object. | `b18fc2c2f887f61452a7c7c7c7048572` | Yes | +| `job.temp_destination` | boolean | A boolean that is true if the message destination is temporary. | | If missing, it is assumed to be false. | +| `job.protocol` | string | The name of the transport protocol. | `AMQP`; `MQTT` | No | +| `job.protocol_version` | string | The version of the transport protocol. | `0.9.1` | No | +| `job.url` | string | Connection string. | `tibjmsnaming://localhost:7222`; `https://queue.amazonaws.com/80398EXAMPLE/MyQueue` | No | +| `job.message_id` | string | A value used by the messaging system as an identifier for the message, represented as a string. | `452a7c7c7c7048c2f887f61572b18fc2` | No | +| `job.conversation_id` | string | The [conversation ID](#conversations) identifying the conversation to which the message belongs, represented as a string. Sometimes called "Correlation ID". | `MyConversationId` | No | +| `job.message_payload_size_bytes` | int | The (uncompressed) size of the message payload in bytes. Also use this attribute if it is unknown whether the compressed or uncompressed payload size is reported. | `2738` | No | +| `job.message_payload_compressed_size_bytes` | int | The compressed size of the message payload in bytes. | `2048` | No | +| [`net.peer.ip`](span-general.md) | string | Remote address of the peer (dotted decimal for IPv4 or [RFC5952](https://tools.ietf.org/html/rfc5952) for IPv6) | `127.0.0.1` | If available. | +| [`net.peer.name`](span-general.md) | string | Remote hostname or similar, see note below. [2] | `example.com` | If available. | + +**[1]:** Required only if the message destination is either a `queue` or `topic`. + +**[2]:** This should be the IP/hostname of the broker (or other network-level peer) this specific message is sent to/received from. + +`messaging.destination_kind` MUST be one of the following: + +| Value | Description | +|---|---| +| `queue` | A message sent to a queue | +| `topic` | A message sent to a topic | + + +Additionally `net.peer.port` from the [network attributes][] is recommended. +Furthermore, it is strongly recommended to add the [`net.transport`][] attribute and follow its guidelines, especially for in-process queueing systems (like [Hangfire][], for example). +These attributes should be set to the broker to which the message is sent/from which it is received. + +[network attributes]: span-general.md#general-network-connection-attributes +[`net.transport`]: span-general.md#nettransport-attribute +[Hangfire]: https://www.hangfire.io/ + +For message consumers, the following additional attributes may be set: + + +| Attribute | Type | Description | Examples | Required | +|---|---|---|---|---| +| `messaging.operation` | string | A string identifying the kind of message consumption as defined in the [Operation names](#operation-names) section above. If the operation is "send", this attribute MUST NOT be set, since the operation can be inferred from the span kind in that case. | `receive` | No | + +`messaging.operation` MUST be one of the following: + +| Value | Description | +|---|---| +| `receive` | receive | +| `process` | process | + + +The _receive_ span is be used to track the time used for receiving the message(s), whereas the _process_ span(s) track the time for processing the message(s). +Note that one or multiple Spans with `messaging.operation` = `process` may often be the children of a Span with `messaging.operation` = `receive`. +The distinction between receiving and processing of messages is not always of particular interest or sometimes hidden away in a framework (see the [Message consumption](#message-consumption) section above) and therefore the attribute can be left out. +For batch receiving and processing (see the [Batch receiving](#batch-receiving) and [Batch processing](#batch-processing) examples below) in particular, the attribute SHOULD be set. +Even though in that case one might think that the processing span's kind should be `INTERNAL`, that kind MUST NOT be used. +Instead span kind should be set to either `CONSUMER` or `SERVER` according to the rules defined above. + +### Attributes specific to certain messaging systems + +#### RabbitMQ + +In RabbitMQ, the destination is defined by an _exchange_ and a _routing key_. +`messaging.destination` MUST be set to the name of the exchange. This will be an empty string if the default exchange is used. +The routing key MUST be provided to the attribute `messaging.rabbitmq.routing_key`, unless it is empty. + +#### Apache Kafka + +For Apache Kafka, the following additional attributes are defined: + + +| Attribute | Type | Description | Examples | Required | +|---|---|---|---|---| +| `messaging.kafka.message_key` | string | Message keys in Kafka are used for grouping alike messages to ensure they're processed on the same partition. They differ from `messaging.message_id` in that they're not unique. If the key is `null`, the attribute MUST NOT be set. [1] | `myKey` | No | +| `messaging.kafka.consumer_group` | string | Name of the Kafka Consumer Group that is handling the message. Only applies to consumers, not producers. | `my-group` | No | +| `messaging.kafka.client_id` | string | Client Id for the Consumer or Producer that is handling the message. | `client-5` | No | +| `messaging.kafka.partition` | int | Partition the message is sent to. | `2` | No | +| `messaging.kafka.tombstone` | boolean | A boolean that is true if the message is a tombstone. | | If missing, it is assumed to be false. | + +**[1]:** If the key type is not string, it's string representation has to be supplied for the attribute. If the key has no unambiguous, canonical string form, don't include its value. + + +For Apache Kafka producers, [`peer.service`](./span-general.md#general-remote-service-attributes) SHOULD be set to the name of the broker or service the message will be sent to. +The `service.name` of a Consumer's Resource SHOULD match the `peer.service` of the Producer, when the message is directly passed to another service. +If an intermediary broker is present, `service.name` and `peer.service` will not be the same. + +## Examples + +### Topic with multiple consumers + +Given is a process P, that publishes a message to a topic T on messaging system MS, and two processes CA and CB, which both receive the message and process it. + +``` +Process P: | Span Prod1 | +-- +Process CA: | Span CA1 | +-- +Process CB: | Span CB1 | +``` + +| Field or Attribute | Span Prod1 | Span CA1 | Span CB1 | +|-|-|-|-| +| Span name | `"T send"` | `"T process"` | `"T process"` | +| Parent | | Span Prod1 | Span Prod1 | +| Links | | | | +| SpanKind | `PRODUCER` | `CONSUMER` | `CONSUMER` | +| Status | `Ok` | `Ok` | `Ok` | +| `net.peer.name` | `"ms"` | `"ms"` | `"ms"` | +| `net.peer.port` | `1234` | `1234` | `1234` | +| `messaging.system` | `"rabbitmq"` | `"rabbitmq"` | `"rabbitmq"` | +| `messaging.destination` | `"T"` | `"T"` | `"T"` | +| `messaging.destination_kind` | `"topic"` | `"topic"` | `"topic"` | +| `messaging.operation` | | `"process"` | `"process"` | +| `messaging.message_id` | `"a1"` | `"a1"`| `"a1"` | + +### Apache Kafka Example + +Given is a process P, that publishes a message to a topic T1 on Apache Kafka. +One process, CA, receives the message and publishes a new message to a topic T2 that is then received and processed by CB. + +``` +Process P: | Span Prod1 | +-- +Process CA: | Span Rcv1 | + | Span Proc1 | + | Span Prod2 | +-- +Process CB: | Span Rcv2 | +``` + +| Field or Attribute | Span Prod1 | Span Rcv1 | Span Proc1 | Span Prod2 | Span Rcv2 +|-|-|-|-|-|-| +| Span name | `"T1 send"` | `"T1 receive"` | `"T1 process"` | `"T2 send"` | `"T2 receive`" | +| Parent | | Span Prod1 | Span Rcv1 | | Span Prod2 | +| Links | | | | Span Prod1 | | +| SpanKind | `PRODUCER` | `CONSUMER` | `CONSUMER` | `PRODUCER` | `CONSUMER` | +| Status | `Ok` | `Ok` | `Ok` | `Ok` | `Ok` | +| `peer.service` | `"myKafka"` | | | `"myKafka"` | | +| `service.name` | | `"myConsumer1"` | `"myConsumer1"` | | `"myConsumer2"` | +| `messaging.system` | `"kafka"` | `"kafka"` | `"kafka"` | `"kafka"` | `"kafka"` | +| `messaging.destination` | `"T1"` | `"T1"` | `"T1"` | `"T2"` | `"T2"` | +| `messaging.destination_kind` | `"topic"` | `"topic"` | `"topic"` | `"topic"` | `"topic"` | +| `messaging.operation` | | `"receive"` | `"process"` | | `"receive"` | +| `messaging.kafka.message_key` | `"myKey"` | `"myKey"` | `"myKey"` | `"anotherKey"` | `"anotherKey"` | +| `messaging.kafka.consumer_group` | | `"my-group"` | `"my-group"` | | `"another-group"` | +| `messaging.kafka.client_id` | | `"5"` | `"5"` | `"5"` | `"8"` | +| `messaging.kafka.partition` | | `"1"` | `"1"` | | `"3"` | + +### Batch receiving + +Given is a process P, that sends two messages to a queue Q on messaging system MS, and a process C, which receives both of them in one batch (Span Recv1) and processes each message separately (Spans Proc1 and Proc2). + +Since a span can only have one parent and the propagated trace and span IDs are not known when the receiving span is started, the receiving span will have no parent and the processing spans are correlated with the producing spans using links. + +``` +Process P: | Span Prod1 | Span Prod2 | +-- +Process C: | Span Recv1 | + | Span Proc1 | + | Span Proc2 | +``` + +| Field or Attribute | Span Prod1 | Span Prod2 | Span Recv1 | Span Proc1 | Span Proc2 | +|-|-|-|-|-|-| +| Span name | `"Q send"` | `"Q send"` | `"Q receive"` | `"Q process"` | `"Q process"` | +| Parent | | | | Span Recv1 | Span Recv1 | +| Links | | | | Span Prod1 | Span Prod2 | +| SpanKind | `PRODUCER` | `PRODUCER` | `CONSUMER` | `CONSUMER` | `CONSUMER` | +| Status | `Ok` | `Ok` | `Ok` | `Ok` | `Ok` | +| `net.peer.name` | `"ms"` | `"ms"` | `"ms"` | `"ms"` | `"ms"` | +| `net.peer.port` | `1234` | `1234` | `1234` | `1234` | `1234` | +| `messaging.system` | `"rabbitmq"` | `"rabbitmq"` | `"rabbitmq"` | `"rabbitmq"` | `"rabbitmq"` | +| `messaging.destination` | `"Q"` | `"Q"` | `"Q"` | `"Q"` | `"Q"` | +| `messaging.destination_kind` | `"queue"` | `"queue"` | `"queue"` | `"queue"` | `"queue"` | +| `messaging.operation` | | | `"receive"` | `"process"` | `"process"` | +| `messaging.message_id` | `"a1"` | `"a2"` | | `"a1"` | `"a2"` | + +### Batch processing + +Given is a process P, that sends two messages to a queue Q on messaging system MS, and a process C, which receives both of them separately (Span Recv1 and Recv2) and processes both messages in one batch (Span Proc1). + +Since each span can only have one parent, C3 should not choose a random parent out of C1 and C2, but rather rely on the implicitly selected parent as defined by the [tracing API spec](../api.md). +Similarly, only one value can be set as `message_id`, so C3 cannot report both `a1` and `a2` and therefore attribute is left out. +Depending on the implementation, the producing spans might still be available in the meta data of the messages and should be added to C3 as links. +The client library or application could also add the receiver span's SpanContext to the data structure it returns for each message. In this case, C3 could also add links to the receiver spans C1 and C2. + +The status of the batch processing span is selected by the application. Depending on the semantics of the operation. A span status `Ok` could, for example, be set only if all messages or if just at least one were properly processed. + +``` +Process P: | Span Prod1 | Span Prod2 | +-- +Process C: | Span Recv1 | Span Recv2 | + | Span Proc1 | +``` + +| Field or Attribute | Span Prod1 | Span Prod2 | Span Recv1 | Span Recv2 | Span Proc1 | +|-|-|-|-|-|-| +| Span name | `"Q send"` | `"Q send"` | `"Q receive"` | `"Q receive"` | `"Q process"` | +| Parent | | | Span Prod1 | Span Prod2 | | +| Links | | | | | Span Prod1 + Prod2 | +| SpanKind | `PRODUCER` | `PRODUCER` | `CONSUMER` | `CONSUMER` | `CONSUMER` | +| Status | `Ok` | `Ok` | `Ok` | `Ok` | `Ok` | +| `net.peer.name` | `"ms"` | `"ms"` | `"ms"` | `"ms"` | `"ms"` | +| `net.peer.port` | `1234` | `1234` | `1234` | `1234` | `1234` | +| `messaging.system` | `"rabbitmq"` | `"rabbitmq"` | `"rabbitmq"` | `"rabbitmq"` | `"rabbitmq"` | +| `messaging.destination` | `"Q"` | `"Q"` | `"Q"` | `"Q"` | `"Q"` | +| `messaging.destination_kind` | `"queue"` | `"queue"` | `"queue"` | `"queue"` | `"queue"` | +| `messaging.operation` | | | `"receive"` | `"receive"` | `"process"` | +| `messaging.message_id` | `"a1"` | `"a2"` | `"a1"` | `"a2"` | | diff --git a/specification/trace/semantic_conventions/messaging.md b/specification/trace/semantic_conventions/messaging.md index 0bfd5d07af5..9d99d0b70f8 100644 --- a/specification/trace/semantic_conventions/messaging.md +++ b/specification/trace/semantic_conventions/messaging.md @@ -57,6 +57,38 @@ For instance, there can be multiple consumer groups processing records from the [idempotent]: https://en.wikipedia.org/wiki/Idempotence +### Disambiguation with Job semantic convention + +There is overlap and potential for confusion between Messaging and Job semantics; + +| Category | Messaging | Job | +| --- | --- | --- | +| Usage of message payload | Only considers message envelope. Does not perform logic based on the payload of the message. | Performs work based on the payload of the message. | +| Message termination | Forwards message to consumer systems. | Consumer (worker) is typically the end of the processing chain. Message is discarded after work is performed. | +| Usage of destination / queue | A Messaging system *must* support some form of destination (queue) or topic . | A Job system *may* | + +Messaging: +* Only considers does not have logic based on the +* Usually + +Does the system forward +Does work happen based on the payload (contents) of the message? + + +that Job systems that have "queues" should use Messaging semantics; that's not a good litmus test. +"Queue" in the context of a Jobs is usually an optional feature. +For example, Ruby's Delayed Job will work all jobs in FIFO order, +but it optionally allows you to set named "queues" and then assign worker resources to specific queues. +Unlike a Messaging system where the queue/topic is the primary feature, in a Job system the queue is an optional/secondary attribute. + +A better litmus test is, "does work happen based on the contents/payload of the message". + +Message system delivers the payload without looking inside; its job is simply to forward the message. +A Job system does work based on the payload; a successfully worked Job is usually the end of the chain (unless a new/different message is generated as a result, e.g. an email sending job.) + +In addition, net.peer.* should still be used here because ultimately traces are sent from physical hosts, +and we want to see which host sent the trace. + ### Message consumption The consumption of a message can happen in multiple steps.