Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Versioned combinators and access_role changes in V3 #2841

Merged
merged 19 commits into from
Dec 2, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions changelog.d/1-api-changes/access-role-v3
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
- The endpoints `POST /conversations/list` and `GET /conversations` have been removed. Use `POST /conversations/list-ids` followed by `POST /conversations/list` instead.
- The endpoint `PUT /conversations/:id/access` has been removed. Use its qualified counterpart instead.
- The field `access_role_v2` in the `Conversation` type, in the request body of `POST /conversations`, and in the request body of `PUT /conversations/:domain/:id/access` has been removed. Its content is now contained in the `access_role` field instead. It replaces the legacy access role, previously contained in the `access_role` field.
- Clients implementing the V3 API must be prepared to handle a change in the format of the conversation.access_update event. Namely, the field access_role_v2 has become optional. When missing, its value is to be found in the field access_role.
49 changes: 49 additions & 0 deletions docs/src/developer/developer/api-versioning.md
Original file line number Diff line number Diff line change
Expand Up @@ -282,3 +282,52 @@ Many variations on this theme are possible. For example, one could choose to
write adapting functions in terms of the new input/output types, or even use a
mixed approach. The adapting functions need not be pure in general, and they
might even perform further RPC calls.

## Versioning changes in events
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is very abstract and could benefit from concrete examples of a timeline including multiple backend and client releases, and at which point changes occur. The way I currently read this is "The backend can make incompatible event changes as long as the client can deal with both the old format and the new format". That just moves the burden of backwards compatibility from the server to the clients, which is not ideal as old versions of clients are around for much longer than old versions of the backend. What am I missing?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, the access_role change in this PR is an example of change X.

I added an example timeline. Not sure it adds anything useful, though, as it's mostly restating the same things with example numbers instead of N and Q.

That just moves the burden of backwards compatibility from the server to the clients, which is not ideal as old versions of clients are around for much longer than old versions of the backend. What am I missing?

The burden of backwards compatibility is shared with this system, and goes away after some time. At first both the backend and the clients have to support two formats. At some point in the future, one of the two can drop the old format. And finally the other one can drop it as well. In fact, the system is pretty symmetric wrt backend and clients.

I agree that it would be nicer to properly version events, but that seems to be quite a major undertaking, and might have some performance implications. This requires some extra bookkeeping, but ultimately achieves the same effect of getting rid of legacy code from all code bases, which is the ultimate goal anyway.


Making incompatible changes to events is also sometimes necessary, or at least
desirable. Unfortunately, there is no direct way to make API versioning
preserve compatibility with older clients when the format of events changes.
This is because the format of events is decided when they are generated, which
is of course before they are fetched by the clients. By the time the backend is
made aware of the version supported by a client, it is too late to change any
logic of event generation or serialisation.

However, there are ways to alter the event API in incompatible ways without
breaking older clients. Namely, we can tie a change X in the format of an event
to a specific api version N. This means that in order for a client to support
version N or later, it has to be able to consume events in any format,
before or after X.

If clients respect this constraint, then the backend only needs to keep the old
format around for as long as version N-1 is supported, and can apply change X as
soon as version N-1 is dropped.

Conversely, clients need to be advised on when it is ok for them to drop their
legacy event parsing code. Unfortunately, determining this point in time is
complicated by the fact that legacy events may be retained by a backend for
some time after it has been upgraded to a version that emits events in the new
format. Therefore, this has to be worked out on a case by case basis.

More precisely: When a new version Q of a backend is released, *if* we can
ensure that no version lower than N is running anywhere in production, and
hasn't been for a time at least as long as the maximum event retention time,
*then* we can drop the requirement for clients to be able to read events in the
legacy format, *as long as they support only versions larger or equal to Q*.

### Example timeline

- While version 3 is in development: a new format for an event is introduced in
the code base, but not yet used for output events, the new format is
documented for clients.
- Version 3 is finalised: events are still produced using the old format;
clients that implement v3 are able to parse both event formats.
- Versions 4 to 6 are finalised. No changes to events.
- Support for version 2 is dropped while version 7 is in development. The old
format can be removed from the code base, and the backend can start producing
events in the new format. No changes in clients are required.
- Version 7 to 9 are finalised. No further changes to events.
- Version 2 or lower is not used in production anymore. Version 10 is currently
in development. The old event format is removed from the documentation.
Clients that support only version 10 or above are not required to understand
the old format anymore.
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ data ConversationCreated conv = ConversationCreated
-- | The conversation type
ccCnvType :: ConvType,
ccCnvAccess :: [Access],
ccCnvAccessRoles :: Set AccessRoleV2,
ccCnvAccessRoles :: Set AccessRole,
-- | The conversation name,
ccCnvName :: Maybe Text,
-- | Members of the conversation apart from the creator
Expand Down
Loading