Skip to content
This repository was archived by the owner on Apr 23, 2021. It is now read-only.

Commit 9611c07

Browse files
ktososlashmo
andauthored
Writeup about context passing style guideline
* Writeup about context passing style guideline Polished version of what we had in slashmo/gsoc-swift-tracing#12 * Update README.md Co-authored-by: Moritz Lang <hi@slashmo.codes> * Update README.md Co-authored-by: Moritz Lang <hi@slashmo.codes> * Update README.md Co-authored-by: Moritz Lang <hi@slashmo.codes> * Update README.md Co-authored-by: Moritz Lang <hi@slashmo.codes> * Update README.md Co-authored-by: Moritz Lang <hi@slashmo.codes> * Update README.md Co-authored-by: Moritz Lang <hi@slashmo.codes> * Update README.md Co-authored-by: Moritz Lang <hi@slashmo.codes>
1 parent 4f086df commit 9611c07

File tree

1 file changed

+67
-1
lines changed

1 file changed

+67
-1
lines changed

README.md

Lines changed: 67 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,73 @@
33
[![Swift 5.2](https://img.shields.io/badge/Swift-5.2-ED523F.svg?style=flat)](https://swift.org/download/)
44
[![CI](https://github.com/slashmo/gsoc-swift-baggage-context/workflows/CI/badge.svg)](https://github.com/slashmo/gsoc-swift-baggage-context/actions?query=workflow%3ACI)
55

6-
`BaggageContext` originated in [this repo](https://github.com/slashmo/gsoc-swift-tracing), but had to be factored out so that we can depend on it in our [NIO fork](https://github.com/slashmo/swift-nio).
6+
`BaggageContext` is a minimal (zero-dependency) "context" library meant to "carry" baggage (metadata) for cross-cutting tools such as tracers.
7+
It is purposefully not tied to any specific use-case (in the spirit of the [Tracing Plane paper](https://cs.brown.edu/~jcmace/papers/mace18universal.pdf)'s BaggageContext), however it should enable a vast majority of use cases cross-cutting tools need to support. Unlike mentioned in the paper, our `BaggageContext` does not implement its own serialization scheme (today).
8+
9+
10+
11+
See https://github.com/slashmo/gsoc-swift-tracing for actual instrument types and implementations which can be used to deploy various cross-cutting instruments all reusing the same baggage type.
12+
13+
## Context-Passing Guidelines
14+
15+
In order for context-passing to feel consistent and Swifty among all server-side (and not only) libraries and frameworks
16+
aiming to adopt `BaggageContext` (or any of its uses, such as Distributed Tracing), we suggest the following set of guidelines:
17+
18+
### Argument naming/positioning
19+
20+
In order to propagate baggage through function calls (and asynchronous-boundaries it may often be necessary to pass it explicitly (unless wrapper APIs are provided which handle the propagation automatically).
21+
22+
When passing baggage context explicitly we strongly suggest sticking to the following style guideline:
23+
24+
- Assuming the general parameter ordering of Swift function is as follows (except DSL exceptions):
25+
1. Required non-function parameters (e.g. `(url: String)`),
26+
2. Defaulted non-function parameters (e.g. `(mode: Mode = .default)`),
27+
3. Required function parameters, including required trailing closures (e.g. `(onNext elementHandler: (Value) -> ())`),
28+
4. Defaulted function parameters, including optional trailing closures (e.g. `(onComplete completionHandler: (Reason) -> ()) = { _ in }`).
29+
- Baggage Context should be passed as: **the last parameter in the required non-function parameters group in a function declaration**.
30+
31+
This way when reading the call side, users of these APIs can learn to "ignore" or "skim over" the context parameter and the method signature remains human-readable and “Swifty”.
32+
33+
Examples:
34+
35+
- `func request(_ url: URL, context: BaggageContext)`, which may be called as `httpClient.request(url, context: context)`
36+
- `func handle(_ request: RequestObject,` **`context: FrameworkContext`** `)`
37+
- if a "framework context" exists and _carries_ the baggage context already, it is permitted to pass that context together with the baggage;
38+
- it is _strongly recommended_ to store the baggage context as `baggage` property of `FrameworkContext` in such cases, in order to avoid the confusing spelling of `context.context`, and favoring the self-explanatory `context.baggage` spelling when the baggage is contained in a framework context object.
39+
- `func receiveMessage(_ message: Message, context: FrameworkContext)`
40+
- `func handle(element: Element,` **`context: FrameworkContext`** `, settings: Settings? = nil)
41+
- before any defaulted non-function parameters
42+
- `func handle(element: Element,` **`context: FrameworkContext`** `, settings: Settings? = nil, onComplete: () -> ())
43+
- before defaulted parameters, which themselfes are before required function parameters
44+
- `func handle(element: Element,` **`context: FrameworkContext`** `, onError: (Error) -> (), onComplete: (() -> ())? = nil)
45+
46+
In case there are _multiple_ "framework-ish" parameters, such as passing a NIO `EventLoop` or similar, we suggest:
47+
48+
- `func perform(_ work: Work, for user: User,` _`frameworkThing: Thing, eventLoop: NIO.EventLoop,`_ **`context: BaggageContext`** `)`
49+
- pass the baggage as **last** of such non-domain specific parameters as it will be _by far more_ omnipresent than any specific framework parameter - as it is expected that any framework should be accepting a context if it is able to do so. While not all libraries are necessarily going to be implemented using the same frameworks.
50+
51+
And lastly
52+
53+
We feel it is important to preserve Swift's human-readable nature of function definitions. In other words, we intend to keep the read-out-loud phrasing of methods to remain _"request that url (ignore reading out loud the context parameter)"_ rather than _"request (ignore this context parameter when reading) that url"_.
54+
55+
56+
#### Existing context argument
57+
58+
When adapting an existing library/framework to support `BaggageContext` and it already has a "framework context" which is expected to be passed through "everywhere", we suggest to follow these guidelines to adopting BaggageContext:
59+
60+
1. Add a `BaggageContext` as a property called `baggage` to your own `context` type, so that the call side for your users becomes `context.baggage` (rather than the confusing `context.context`)
61+
2. If you cannot or it would not make sense to carry baggage inside your framework's context object, pass (and accept (!)) the `BaggageContext` in your framework functions like follows:
62+
- if they take no framework context, accept a `context: BaggageContext` which is the same guideline as for all other cases
63+
- if they already _must_ take a context object and you are out of words (or your API already accepts your framework context as "context"), pass the baggage as **last** parameter (see above) yet call the parameter `baggage` to disambiguate your `context` object from the `baggage` context object.
64+
65+
Examples:
66+
67+
- `Lamda.Context` may contain `baggage` and this way offer traceIDs and other values
68+
- passing context to a `Lambda.Context` unaware library becomes: `http.request(url: "...", context: context.baggage)`.
69+
- TODO: We are considering a protocol which would simplify this if it is known that Lambda.Context "carries" baggage...
70+
- `ChannelHandlerContext` offers a way to set/get baggage on the underlying channel via `context.baggage = ...`
71+
- WorkInProgress, see: https://github.com/apple/swift-nio/pull/1574
72+
773

874
## Contributing
975

0 commit comments

Comments
 (0)