This commit is contained in:
Neil Alexander 2022-08-31 16:28:53 +01:00
parent 050a10d539
commit e80596effb
No known key found for this signature in database
GPG key ID: A02A2019A2BB0944

View file

@ -79,7 +79,8 @@ func (s *OutputRoomEventConsumer) Start() error {
token := jetstream.Tokenise(as.ID) token := jetstream.Tokenise(as.ID)
if err := jetstream.JetStreamConsumer( if err := jetstream.JetStreamConsumer(
s.ctx, s.jetstream, s.topic, s.ctx, s.jetstream, s.topic,
s.cfg.Matrix.JetStream.Durable("Appservice_"+token), 50, s.cfg.Matrix.JetStream.Durable("Appservice_"+token),
50, // maximum number of events to send in a single transaction
func(ctx context.Context, msgs []*nats.Msg) bool { func(ctx context.Context, msgs []*nats.Msg) bool {
return s.onMessage(ctx, state, msgs) return s.onMessage(ctx, state, msgs)
}, },
@ -96,7 +97,7 @@ func (s *OutputRoomEventConsumer) Start() error {
func (s *OutputRoomEventConsumer) onMessage( func (s *OutputRoomEventConsumer) onMessage(
ctx context.Context, state *appserviceState, msgs []*nats.Msg, ctx context.Context, state *appserviceState, msgs []*nats.Msg,
) bool { ) bool {
log.WithField("appservice", state.ID).Debugf("Appservice worker received %d message(s) from roomserver", len(msgs)) log.WithField("appservice", state.ID).Tracef("Appservice worker received %d message(s) from roomserver", len(msgs))
events := make([]*gomatrixserverlib.HeaderedEvent, 0, len(msgs)) events := make([]*gomatrixserverlib.HeaderedEvent, 0, len(msgs))
for _, msg := range msgs { for _, msg := range msgs {
// Parse out the event JSON // Parse out the event JSON
@ -108,10 +109,7 @@ func (s *OutputRoomEventConsumer) onMessage(
} }
switch output.Type { switch output.Type {
case api.OutputTypeNewRoomEvent: case api.OutputTypeNewRoomEvent:
if output.NewRoomEvent == nil { if output.NewRoomEvent == nil || !s.appserviceIsInterestedInEvent(ctx, output.NewRoomEvent.Event, state.ApplicationService) {
continue
}
if !s.appserviceIsInterestedInEvent(ctx, output.NewRoomEvent.Event, state.ApplicationService) {
continue continue
} }
events = append(events, output.NewRoomEvent.Event) events = append(events, output.NewRoomEvent.Event)
@ -147,19 +145,16 @@ func (s *OutputRoomEventConsumer) onMessage(
} }
// If there are no events selected for sending then we should // If there are no events selected for sending then we should
// ack the events so that we don't get sent them again in the // ack the messages so that we don't get sent them again in the
// future. // future.
if len(events) == 0 { if len(events) == 0 {
return true return true
} }
// Send event to any relevant application services // Send event to any relevant application services. If we hit
if err := s.sendEvents(ctx, state, events); err != nil { // an error here, return false, so that we negatively ack.
log.WithField("appservice", state.ID).WithError(err).Errorf("Appservice failed to send events") log.WithField("appservice", state.ID).Debugf("Appservice worker sending %d events(s) from roomserver", len(events))
return false return s.sendEvents(ctx, state, events) == nil
}
return true
} }
// sendEvents passes events to the appservice by using the transactions // sendEvents passes events to the appservice by using the transactions
@ -168,16 +163,12 @@ func (s *OutputRoomEventConsumer) sendEvents(
ctx context.Context, state *appserviceState, ctx context.Context, state *appserviceState,
events []*gomatrixserverlib.HeaderedEvent, events []*gomatrixserverlib.HeaderedEvent,
) error { ) error {
// If there are no events that we are interested in then don't bother
// doing anything else at this point.
if len(events) == 0 {
return nil
}
// Create the transaction body. // Create the transaction body.
transaction, err := json.Marshal(gomatrixserverlib.ApplicationServiceTransaction{ transaction, err := json.Marshal(
Events: gomatrixserverlib.HeaderedToClientEvents(events, gomatrixserverlib.FormatAll), gomatrixserverlib.ApplicationServiceTransaction{
}) Events: gomatrixserverlib.HeaderedToClientEvents(events, gomatrixserverlib.FormatAll),
},
)
if err != nil { if err != nil {
return err return err
} }
@ -196,8 +187,7 @@ func (s *OutputRoomEventConsumer) sendEvents(
req.Header.Set("Content-Type", "application/json") req.Header.Set("Content-Type", "application/json")
resp, err := s.client.Do(req) resp, err := s.client.Do(req)
if err != nil { if err != nil {
state.backoffAndPause(err) return state.backoffAndPause(err)
return err
} }
// If the response was fine then we can clear any backoffs in place and // If the response was fine then we can clear any backoffs in place and
@ -206,20 +196,20 @@ func (s *OutputRoomEventConsumer) sendEvents(
case http.StatusOK: case http.StatusOK:
state.backoff = 0 state.backoff = 0
default: default:
state.backoffAndPause(err) _ = state.backoffAndPause(err)
} }
return nil return nil
} }
// backoff pauses the calling goroutine for a 2^some backoff exponent seconds // backoff pauses the calling goroutine for a 2^some backoff exponent seconds
func (s *appserviceState) backoffAndPause(err error) { func (s *appserviceState) backoffAndPause(err error) error {
if s.backoff < 6 { if s.backoff < 6 {
s.backoff++ s.backoff++
} }
duration := time.Second * time.Duration(math.Pow(2, float64(s.backoff))) duration := time.Second * time.Duration(math.Pow(2, float64(s.backoff)))
log.WithField("appservice", s.ID).WithError(err).Warnf("Unable to send transaction to appservice successfully, backing off for %s", duration.String()) log.WithField("appservice", s.ID).WithError(err).Warnf("Unable to send transaction to appservice successfully, backing off for %s", duration.String())
time.Sleep(duration) time.Sleep(duration)
return err
} }
// appserviceIsInterestedInEvent returns a boolean depending on whether a given // appserviceIsInterestedInEvent returns a boolean depending on whether a given
@ -227,15 +217,12 @@ func (s *appserviceState) backoffAndPause(err error) {
// //
// TODO: This should be cached, see https://github.com/matrix-org/dendrite/issues/1682 // TODO: This should be cached, see https://github.com/matrix-org/dendrite/issues/1682
func (s *OutputRoomEventConsumer) appserviceIsInterestedInEvent(ctx context.Context, event *gomatrixserverlib.HeaderedEvent, appservice *config.ApplicationService) bool { func (s *OutputRoomEventConsumer) appserviceIsInterestedInEvent(ctx context.Context, event *gomatrixserverlib.HeaderedEvent, appservice *config.ApplicationService) bool {
// No reason to queue events if they'll never be sent to the application switch {
// service case appservice.URL == "":
if appservice.URL == "" {
return false return false
} case appservice.IsInterestedInUserID(event.Sender()):
return true
// Check Room ID and Sender of the event case appservice.IsInterestedInRoomID(event.RoomID()):
if appservice.IsInterestedInUserID(event.Sender()) ||
appservice.IsInterestedInRoomID(event.RoomID()) {
return true return true
} }
@ -256,7 +243,8 @@ func (s *OutputRoomEventConsumer) appserviceIsInterestedInEvent(ctx context.Cont
} }
} else { } else {
log.WithFields(log.Fields{ log.WithFields(log.Fields{
"room_id": event.RoomID(), "appservice": appservice.ID,
"room_id": event.RoomID(),
}).WithError(err).Errorf("Unable to get aliases for room") }).WithError(err).Errorf("Unable to get aliases for room")
} }
@ -291,7 +279,8 @@ func (s *OutputRoomEventConsumer) appserviceJoinedAtEvent(ctx context.Context, e
} }
} else { } else {
log.WithFields(log.Fields{ log.WithFields(log.Fields{
"room_id": event.RoomID(), "appservice": appservice.ID,
"room_id": event.RoomID(),
}).WithError(err).Errorf("Unable to get membership for room") }).WithError(err).Errorf("Unable to get membership for room")
} }
return false return false