Example #1
0
// proxyMessages forwards a set of pubsub messages to the endpoint proxy.
func (a *application) proxyMessages(ctx context.Context, msgs []*pubsub.Message) error {
	log.Fields{
		"size": len(msgs),
	}.Debugf(ctx, "Sending messages to Proxy.")

	// TODO: Batch messages together into larger pushes.
	// TODO: Validate messages.
	err := parallel.FanOutIn(func(c chan<- func() error) {
		for idx, msg := range msgs {
			msg := msg
			c <- func() error {
				ctx := log.SetFields(ctx, log.Fields{
					"size":      len(msg.Data),
					"messageID": msg.ID,
				})

				err := a.proxySingleMessage(ctx, msg)

				// If we hit a transient error, set the message's element to nil,
				// causing it to not be ACKed.
				if err != nil {
					transient := luciErrors.IsTransient(err)
					log.Fields{
						log.ErrorKey: err,
						"transient":  transient,
					}.Errorf(ctx, "Error when pushing message.")
					if transient {
						msgs[idx] = nil
					}
				}
				return err
			}
		}
	})

	merr, _ := err.(luciErrors.MultiError)
	log.Fields{
		"errorStatus": err,
		"count":       len(msgs),
		"errorCount":  len(merr),
	}.Infof(ctx, "Sent messages to endpoint.")
	return err
}
Example #2
0
// Next implements the Iterator interface.
func (i *TransientOnly) Next(ctx context.Context, err error) time.Duration {
	if !errors.IsTransient(err) {
		return Stop
	}
	return i.Iterator.Next(ctx, err)
}
Example #3
0
// TestEndpoint tests the endpoint implementation and API.
func TestEndpointService(t *testing.T) {
	t.Parallel()

	Convey(`An endpoint service connected to a testing HTTP server`, t, func() {
		ctx, tc := testclock.UseTime(context.Background(), time.Date(2015, 1, 1, 0, 0, 0, 0, time.UTC))

		// Retry up to ten times without delaying.
		ctx = context.WithValue(ctx, backoffPolicyKey, func() retry.Iterator {
			return &retry.Limited{Retries: 10}
		})

		h := &testEndpointServiceHandler{}
		srv := httptest.NewTLSServer(h)
		defer srv.Close()

		tr := &http.Transport{
			TLSClientConfig: &tls.Config{
				InsecureSkipVerify: true,
			},
		}
		client := &http.Client{
			Transport: tr,
		}

		c := &endpointServiceImpl{
			endpointConfig: endpointConfig{url: srv.URL},
			client:         client,
		}

		msg := bytes.Repeat([]byte{0x60, 0x0d, 0xd0, 0x65}, 32)
		Convey(`Successfully posts a message.`, func() {
			So(c.send(ctx, msg), ShouldBeNil)

			So(h.connections, ShouldEqual, 1)
			So(h.errors, ShouldEqual, 0)
			So(h.messages, ShouldResemble, [][]byte{msg})
		})

		Convey(`Retries sending when an error is encountered.`, func() {
			tc.SetTimerCallback(func(t clock.Timer) {
				tc.Add(time.Second)
			})
			h.failures = 4
			So(c.send(ctx, msg), ShouldBeNil)

			So(h.connections, ShouldEqual, 5)
			So(h.errors, ShouldEqual, 4)
			So(h.messages, ShouldResemble, [][]byte{msg})
		})

		Convey(`Returns a transient error when a send completely fails.`, func() {
			h.failures = 11
			err := c.send(ctx, msg)
			So(err, ShouldNotBeNil)
			So(errors.IsTransient(err), ShouldBeTrue)

			So(h.connections, ShouldEqual, 11)
			So(h.errors, ShouldEqual, 11)
			So(h.messages, ShouldResemble, [][]byte(nil))
		})
	})
}