Glides Events
Information about Green Line operations, such as trainsheets, published by Glides.
Originally defined in RFC 18. This documentation supercedes that RFC.
These events are primarily published so that RTR can consume it to improve public predictions and realtime data. Other applications may find other uses for the data.
Events
trips_updated
Published when Glides has new information about trips, for example operator assignments or dropped trips. Consumers who want to know what trains are running should pay attention to this event, and don't need to pay attention to any other events.
📄️ com.mbta.ctd.glides.trips_updated.v1
event type: com.mbta.ctd.glides.trips_updated.v1
vehicle_trip_assignment
Realtime information about which train is currently running which trip.
📄️ com.mbta.ctd.glides.vehicle_trip_assignment.v1
event type: com.mbta.ctd.glides.vehicletripassignment.v1
editors_changed
Published when there's a change to which inspectors are editing a trainsheet.
📄️ com.mbta.ctd.glides.editors_changed.v1
event type: com.mbta.ctd.glides.editors_changed.v1
operator_signed_in
Published when an operator signs in as fit for duty.
📄️ com.mbta.ctd.glides.operator_signed_in.v1
event type: com.mbta.ctd.glides.operatorsignedin.v1
Shared Types
Types used by multiple of the events are documented here. Types used by only one of the events are documented on each event page.
GlidesUser
Fields:
emailAddress
(string): the e-mail of the user.badgeNumber
(string, optional): the badge number of the user. Not all Glides users have a badge number (for example, CTD contractors).
Location
One of:
{"gtfsId": "<GTFS stop ID>"}
, where the GTFSlocation_type
is1
(station). Glides doesn't differentiate between children of GTFS stops, so won't publish any GTFS child stop IDs.{"todsId": "<TODS stop ID"}
: ID corresponding toops_location_id
in the upcoming TODS data. These stops'location_type
may be0
(stop) or1
(station).
Metadata
Information about how the event was created by Glides. All important outputs from Glides will be elsewhere in the event data, but data here might be useful for consumers who care about how inspectors are using Glides.
All fields are optional and Glides MAY choose not to include any of them on any event.
Fields:
author
(GlidesUser, optional): The logged-in user whose action triggered the event.inputTimestamp
(RFC3999 timestamp, optional): The timestamp that the user entered the data into Glides, as reported by their device. You probably want to use the event time instead. See more explanation below.inputType
(string, optional): the action that the user did in Glides. This field exists because the event data on its own may not specify how the data was entered, for example all trainsheet updates are normalized into a generic format intripUpdates
. Example values for this field are"add-trip"
or"manage-headways"
, but no guarantees are given about what strings will be used or which actions the field will be populated for.location
(Location, optional): the location the logged-in user is managing.
A note about inputTimestamp
The inputTimestamp
field is reported by the Glides user's device, and is different from the time
field in the event, which is the server-reported time that the Glides server received the input.
They could differ if sending the input was delayed due to network problems, or if the device's clock is wrong.
Consumers are recommended to use the server-reported event time for most use cases, and not this client-reported inputTimestamp
field, because:
- The
inputTimestamp
is generated by the client device, and so is in some sense less trustworthy. What if a client's clock is set wrong? We don't do any validation, and we can't, because we can't tell the difference between an incorrect time and a correct time that was delayed by network issues. This isn't so much a specific concern as a general practice of not depending on non-validated client data. - Glides applies updates in the order they're received. If a consumer applies events based on client-provided timestamps, they could apply events in a different order than Glides and end up with incorrect results about the state of a trip.
- The CloudEvents docs seem to say that the event time's consistency is more important than it being the original occurence time. Server-provided times will be more consistent than client-provided times.
CloudEvents suggests
that the event time should be "when the occurence happened", which would be when the input was made,
but for the reasons above, Glides uses a server-reported time as the event time and separates the client-reported inputTime
into metadata
.
Operator
Fields:
badgeNumber
(string)
MAY refer to other non-operator Area 132 employees in some cases, for example if an inspector signs in as fit for duty in Glides (they aren't required to).
It is represented as an object to provide future extensibility if needed.
Details
Events are in the CloudEvents format, and published via AWS Kinesis. See RFC 19 Event Driven Architecture for more about CTD's approach to publishing events.
Kinesis
Events will be written as records to a Kinesis stream. Each Glides environment (dev
, dev-green
, and prod
) will have a separate stream, named ctd-glides-<environment>
.
The partition key will be a hash of the station at which the inspector is working and the inspector's identity, which ensures that multiple events from a single inspector are ordered correctly if the records are distributed across multiple shards.
Multiple events can be included in a single Kinesis record, by wrapping them in a JSON array. This is an optimization for improving write speeds: further steps in the Kinesis pipeline may break up or rearrange these arrays.
Kinesis only adds a limited (<1s) latency between when the event is generated and when it is available to consumers.
Short-term storage
Events are only maintained in Kinesis for 24 hours. Some events (such as a trips_updated which modifies the operators) can affect trips more than 24 hours in the future. Clients SHOULD maintain records internally of these future changes. Clients MUST NOT expect that reading the Kinesis stream from the trim horizon will return all events affecting the current service day. Clients MUST tolerate receiving updates for events that reference unseen past events (such as an update to an added trip that the client did not see get added, or a editors_changed
event that stops editing for an inspector the client did not see start editing).
Long-term storage
LAMP is planning to archive these events in AWS S3 for future use.
As the stream contains potential PII (operator badge information) any long-term storage (S3, database) MUST be encrypted at rest.
Compatibility
These event schemas may be updated, according to RFC 19 Event Driven Architecture #Compatibility.
A change is backwards-compatible if all old events are valid with the new schema, all new events are valid with the old schema, and their semantics have not changed. In that case, Glides MAY publish events with the new format without warning, and the event version number will not be bumped.
In the case of a backwards-incompatible change, a new event type
MUST be created (probably by bumping the v1
version number). Glides MUST continue to generate old events alongside the new events until no more consumers depend on the old version.
In either case, this documentation MUST be updated.
Examples of backwards-compatible changes:
- Adding an optional
reason
field to TripAdded. - Adding a new event
type
(which is not replacing an existing eventtype
).
Consumer Responsibilities
- Consumers MUST ignore event
type
s that they do not understand. - Consumers MUST ignore fields in events (and in nested objects in events) which they do not understand, trusting that any additional fields are not required to process the event.
- Consumers SHOULD ignore earlier versions of the same event if they can parse a later version (i.e. ignoring
v1
events if they can parsev2
).
Idempotence
All Glides events are idempotent (and to remove that promise would be a non backwards compatible change).
If an event is submitted to the stream twice, due to a network error, then the events will have the same event id, and the same data. Clients MAY ignore duplicate events, however, they can safely replay events if they occur in short succession.
A TripAdded will not have the same TripKey as a previous TripAdded event, unless it's a duplicate due to a network error, in which case the event will be identical. A client who recieves duplicate events with TripAdded SHOULD take care not to add two trips.
A client who receives duplicate OperatorSignedIn events SHOULD take care not to add two signatures. Clients MAY do this by assuming that if two OperatorSignedIn events have the same operator
and signedInAt
, then they are duplicates.