I want to clarify the relationship between messaging, RPC, and FaaS which is confusing to me right now. Let me give an example, based on my understanding of the current spec, and let me know if this aligns with expectations. This is an example of lambda + sqs, something I'm working on now and is sufficiently complicated that hopefully other cases are simpler.
SQS - an HTTP-based RPC API for publishing and receiving messages
Lambda - a FaaS that can be integrated with SQS. Lambda runtime polls for messages using SQS's RPC API, and when a message comes in, it runs a function with the received batch of messages
SQS Queue - NiceQueue
Lambda function - process_function
So I can invision many spans. These are all for the same request so up to the producer spans is all in the same trace
Request - Request span for the "trace", with current span lasts until end of production
Message1 - Message 1
Message2 - Message 2
Producer1 - Producer Span for Message 1
Producer2 - Producer Span for Message 2
APIPublish1 - Client span using SQS API to send Message1
APIPublish2 - Client span using SQS API to send Message2
PollMessages - Internal, infinite? span that corresponds to the lambda runtime process itself
APIReceive - Client span using SQS API to poll for messages and receive Message 1 and 2
FaaSInitialize - Span encompassing lambda function initialization and invocation. May have cold start
FaaSInvoke - Span encompassing lambda function invocation by runtime
FaasFunction - Span encmpassing lambda function execution in user's app
Receive - Consumer span encompassing the recived batch
Process1 - Processing span for Message1
Process2 - Processing span for Message2
Trace 1
|--------------------------OrderService.ProcessOrders-------------------------|
|NiceQueue send| |NiceQueue send|
|SQS.SendMessage| |SQS.SendMessage|
Trace 2
|-------------------------pollmessages------------------------------------------------------------------------------------------|
|APIReceive||APIReceive||APIReceive||APIReceive||APIReceive||APIReceive||APIReceive|
|-----FaaSInitialize-----------------|
|---FaasInvoke--------------|
|---FaasFunction------------|
|--Receive--------------|
|Process1||Process2|
Phew lots of spans. So does it look like this?
| id |
name |
kind |
duration |
parent |
link |
semantic types |
owner |
| Request |
OrderService.ProcessOrders |
SERVER |
50ms |
none |
none |
rpc,http |
user |
| Producer1 |
NiceQueue send |
PRODUCER |
0 |
Request |
none |
messaging |
user |
| ApiPublish1 |
SQS.SendMessage |
CLIENT |
20ms |
Producer1 |
none |
rpc,http |
user |
| Producer2 |
NiceQueue send |
PRODUCER |
0 |
Request |
none |
messaging |
user |
| ApiPublish2 |
SQS.SendMessage |
CLIENT |
20ms |
Producer2 |
none |
rpc, http |
user |
| PollMessages |
pollmessages |
INTERNAL |
infinity |
none |
none |
none |
infra |
| APIReceive |
SQS.ReceiveMessage |
CLIENT |
30ms |
PollMessages |
none |
rpc, http |
infra |
| FaaSInitialize |
Lambda::Initialize |
INTERNAL |
500ms |
none |
none |
none |
infra |
| FaaSInvoke |
Lambda::Invoke |
INTERNAL |
300ms |
FaasInitialize |
none |
none |
infra |
| FaaSFunction |
process_function |
INTERNAL |
300ms |
FaaSInvoke |
none |
faas |
user |
| Receive |
NiceQueue receive |
CONSUMER |
250ms |
FaaSFunction |
none |
messaging |
user |
| Process1 |
NiceQueue process |
CONSUMER |
100ms |
Receive |
Producer1 |
messaging |
user |
| Process2 |
NiceQueue process |
CONSUMER |
100ms |
Receive |
Producer2 |
messaging |
user |
My currently open questions
-
This is an ideal case, but especially when using auto instrumentation, it may not be possible to have Process1 and Process2 - Lambda presents the entire batch to the user. Should Receive also have links to Producer1 and Producer2? Should Receive be a process span instead of a receive span?
-
How to connect the API calls and the messaging spans. Completely separate like I listed? It means there are mysterious 0 duration producer spans and APIPublish are child or PRODUCER. Or combine e.g., Producer1 and ApiPublish1? Would the name be NiceQueue.send but we still include rpc.service == SQS, rpc.method == SendMessage to not lose that information? Is such a span's kind producer or client?
-
Are FaaSInvoke and Receive separate or should be combined? In reality, if the runtime is a cloud provider, there may not be control and FaasInvoke is automatically created.
-
APIReceive is a CLIENT span so I wouldn't expect it to be a parent of the rest - is it basically an orphan span? Anyways, while I may be able to model it as a parent of something if I was implementing all this myself, it wouldn't be for lambda = SQS.
Appreciate any guidance :)
I want to clarify the relationship between messaging, RPC, and FaaS which is confusing to me right now. Let me give an example, based on my understanding of the current spec, and let me know if this aligns with expectations. This is an example of lambda + sqs, something I'm working on now and is sufficiently complicated that hopefully other cases are simpler.
SQS - an HTTP-based RPC API for publishing and receiving messages
Lambda - a FaaS that can be integrated with SQS. Lambda runtime polls for messages using SQS's RPC API, and when a message comes in, it runs a function with the received batch of messages
SQS Queue - NiceQueue
Lambda function - process_function
So I can invision many spans. These are all for the same request so up to the producer spans is all in the same trace
Request - Request span for the "trace", with current span lasts until end of production
Message1 - Message 1
Message2 - Message 2
Producer1 - Producer Span for Message 1
Producer2 - Producer Span for Message 2
APIPublish1 - Client span using SQS API to send Message1
APIPublish2 - Client span using SQS API to send Message2
PollMessages - Internal, infinite? span that corresponds to the lambda runtime process itself
APIReceive - Client span using SQS API to poll for messages and receive Message 1 and 2
FaaSInitialize - Span encompassing lambda function initialization and invocation. May have cold start
FaaSInvoke - Span encompassing lambda function invocation by runtime
FaasFunction - Span encmpassing lambda function execution in user's app
Receive - Consumer span encompassing the recived batch
Process1 - Processing span for Message1
Process2 - Processing span for Message2
Phew lots of spans. So does it look like this?
My currently open questions
This is an ideal case, but especially when using auto instrumentation, it may not be possible to have
Process1andProcess2- Lambda presents the entire batch to the user. ShouldReceivealso have links toProducer1andProducer2? Should Receive be a process span instead of a receive span?How to connect the API calls and the messaging spans. Completely separate like I listed? It means there are mysterious 0 duration producer spans and APIPublish are child or PRODUCER. Or combine e.g.,
Producer1andApiPublish1? Would the name beNiceQueue.sendbut we still includerpc.service == SQS,rpc.method == SendMessageto not lose that information? Is such a span's kind producer or client?Are
FaaSInvokeandReceiveseparate or should be combined? In reality, if the runtime is a cloud provider, there may not be control andFaasInvokeis automatically created.APIReceiveis a CLIENT span so I wouldn't expect it to be a parent of the rest - is it basically an orphan span? Anyways, while I may be able to model it as a parent of something if I was implementing all this myself, it wouldn't be for lambda = SQS.Appreciate any guidance :)