Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
615ba5bf72 |
+4
-5
@@ -274,12 +274,11 @@ EXPOSE 8080
|
|||||||
# port.
|
# port.
|
||||||
ENV BIND_ADDRESS=0.0.0.0
|
ENV BIND_ADDRESS=0.0.0.0
|
||||||
|
|
||||||
# The probe requests the container's own address, not loopback, so a
|
# The address is 127.0.0.1 because wget tries only the first address
|
||||||
# listener that answers only on loopback (an empty or loopback
|
# localhost resolves to. That can be ::1, which a 0.0.0.0 bind does
|
||||||
# BIND_ADDRESS) fails it. hostname -i prints one IPv4 address per
|
# not answer.
|
||||||
# network the container is on; the first is enough.
|
|
||||||
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
|
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
|
||||||
CMD wget --no-verbose --tries=1 --spider "http://$(hostname -i | cut -d ' ' -f 1):8080/.well-known/healthcheck" || exit 1
|
CMD wget --no-verbose --tries=1 --spider http://127.0.0.1:8080/.well-known/healthcheck || exit 1
|
||||||
|
|
||||||
ENTRYPOINT ["/usr/local/bin/docker-entrypoint.sh"]
|
ENTRYPOINT ["/usr/local/bin/docker-entrypoint.sh"]
|
||||||
CMD ["/app/webhooker"]
|
CMD ["/app/webhooker"]
|
||||||
|
|||||||
@@ -667,10 +667,10 @@ Either set a literal or leave the variable out entirely.
|
|||||||
|
|
||||||
Overriding `BIND_ADDRESS` to a loopback address in a container — by that route
|
Overriding `BIND_ADDRESS` to a loopback address in a container — by that route
|
||||||
or deliberately — makes the container unreachable from outside its namespace
|
or deliberately — makes the container unreachable from outside its namespace
|
||||||
even with `-p`. The published port answers nothing, and the health check fails
|
even with `-p`. The published port answers nothing. The health check requests
|
||||||
too: it requests the container's own address (the first one `hostname -i`
|
`http://127.0.0.1:8080` from inside the container, so a `127.0.0.1` bind passes
|
||||||
prints), where a loopback bind is not listening. The container then goes
|
it and the container stays `healthy`. A `::1` bind fails it, and the container
|
||||||
`unhealthy` about **65 seconds** after start — from
|
goes `unhealthy` about **65 seconds** after start — from
|
||||||
`HEALTHCHECK --start-period=5s --interval=30s --retries=3`, so failing probes at
|
`HEALTHCHECK --start-period=5s --interval=30s --retries=3`, so failing probes at
|
||||||
5s, 35s and 65s, and `unhealthy` on the third. (Docker's probe cadence during
|
5s, 35s and 65s, and `unhealthy` on the third. (Docker's probe cadence during
|
||||||
the start period has changed between versions; re-derive from those three values
|
the start period has changed between versions; re-derive from those three values
|
||||||
@@ -726,8 +726,8 @@ the credentials.
|
|||||||
address (directly, or through anything that can rewrite source addresses,
|
address (directly, or through anything that can rewrite source addresses,
|
||||||
such as NAT or a published container port). The `remoteIP` field of the
|
such as NAT or a published container port). The `remoteIP` field of the
|
||||||
`http request` log line for a request that came through the proxy shows
|
`http request` log line for a request that came through the proxy shows
|
||||||
that address; the health check's own lines show the container's own
|
that address; the health check's own lines show `127.0.0.1`. See
|
||||||
address. See [Trusted proxies](#trusted-proxies).
|
[Trusted proxies](#trusted-proxies).
|
||||||
- Leave `BIND_ADDRESS` and `DATA_DIR` unset: the image sets `BIND_ADDRESS`
|
- Leave `BIND_ADDRESS` and `DATA_DIR` unset: the image sets `BIND_ADDRESS`
|
||||||
to `0.0.0.0`, and `DATA_DIR` defaults to `/var/lib/webhooker`.
|
to `0.0.0.0`, and `DATA_DIR` defaults to `/var/lib/webhooker`.
|
||||||
- Everything else is optional; see [Configuration](#configuration).
|
- Everything else is optional; see [Configuration](#configuration).
|
||||||
|
|||||||
@@ -32,9 +32,8 @@ func targetTotals(
|
|||||||
|
|
||||||
// TestUpdateDeliveryStatus_FinishTimeAndTargetTotals pins what a status
|
// TestUpdateDeliveryStatus_FinishTimeAndTargetTotals pins what a status
|
||||||
// write records for the webhook page's statistics: the time a delivery
|
// write records for the webhook page's statistics: the time a delivery
|
||||||
// finished, set only when it becomes delivered or failed and stored in
|
// finished, set only when it becomes delivered or failed, and one more
|
||||||
// the same form as created_at, and one more on its target's delivered
|
// on its target's delivered or failed total.
|
||||||
// or failed total.
|
|
||||||
func TestUpdateDeliveryStatus_FinishTimeAndTargetTotals(t *testing.T) {
|
func TestUpdateDeliveryStatus_FinishTimeAndTargetTotals(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
@@ -76,16 +75,6 @@ func TestUpdateDeliveryStatus_FinishTimeAndTargetTotals(t *testing.T) {
|
|||||||
if tt.finished {
|
if tt.finished {
|
||||||
require.NotNil(t, stored.FinishedAt)
|
require.NotNil(t, stored.FinishedAt)
|
||||||
assert.False(t, stored.FinishedAt.Before(before))
|
assert.False(t, stored.FinishedAt.Before(before))
|
||||||
|
|
||||||
var createdAt, finishedAt string
|
|
||||||
|
|
||||||
require.NoError(t, db.Raw(
|
|
||||||
`SELECT CAST(created_at AS TEXT),
|
|
||||||
CAST(finished_at AS TEXT)
|
|
||||||
FROM deliveries WHERE id = ?`, d.ID,
|
|
||||||
).Row().Scan(&createdAt, &finishedAt))
|
|
||||||
assertStoredTime(t, createdAt)
|
|
||||||
assertStoredTime(t, finishedAt)
|
|
||||||
} else {
|
} else {
|
||||||
assert.Nil(t, stored.FinishedAt)
|
assert.Nil(t, stored.FinishedAt)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1701,11 +1701,8 @@ func writeDeliveryStatus(
|
|||||||
database.DeliveryStatusFailed,
|
database.DeliveryStatusFailed,
|
||||||
}).
|
}).
|
||||||
Updates(map[string]any{
|
Updates(map[string]any{
|
||||||
"status": status,
|
"status": status,
|
||||||
// GORM's clock, the one that stamps created_at. A bare
|
"finished_at": time.Now(),
|
||||||
// time.Now() carries a monotonic clock reading, which the
|
|
||||||
// driver would store as an " m=+…" suffix.
|
|
||||||
"finished_at": tx.NowFunc(),
|
|
||||||
})
|
})
|
||||||
if res.Error != nil || res.RowsAffected == 0 {
|
if res.Error != nil || res.RowsAffected == 0 {
|
||||||
return res.Error
|
return res.Error
|
||||||
@@ -1909,13 +1906,12 @@ func (e *Engine) takeForRedispatch(
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// GORM's clock, as writeDeliveryStatus explains.
|
|
||||||
res := webhookDB.
|
res := webhookDB.
|
||||||
Model(&database.Delivery{}).
|
Model(&database.Delivery{}).
|
||||||
Where(
|
Where(
|
||||||
"id = ? AND status = ?", deliveryID, eligible,
|
"id = ? AND status = ?", deliveryID, eligible,
|
||||||
).
|
).
|
||||||
UpdateColumn("updated_at", webhookDB.NowFunc())
|
UpdateColumn("updated_at", time.Now())
|
||||||
|
|
||||||
if res.Error != nil {
|
if res.Error != nil {
|
||||||
e.log.Error(
|
e.log.Error(
|
||||||
|
|||||||
@@ -117,18 +117,6 @@ func seedDelivery(
|
|||||||
return d
|
return d
|
||||||
}
|
}
|
||||||
|
|
||||||
// assertStoredTime asserts that text, a timestamp as SQLite holds it,
|
|
||||||
// is in the form GORM stores created_at in: the layout of
|
|
||||||
// time.Time.String, with no " m=+…" monotonic clock reading after it.
|
|
||||||
func assertStoredTime(t *testing.T, text string) {
|
|
||||||
t.Helper()
|
|
||||||
|
|
||||||
_, err := time.Parse(
|
|
||||||
"2006-01-02 15:04:05.999999999 -0700 MST", text,
|
|
||||||
)
|
|
||||||
assert.NoError(t, err, "stored as %q", text)
|
|
||||||
}
|
|
||||||
|
|
||||||
// httpDeliveryFixture holds the task and delivery needed
|
// httpDeliveryFixture holds the task and delivery needed
|
||||||
// for HTTP delivery tests.
|
// for HTTP delivery tests.
|
||||||
type httpDeliveryFixture struct {
|
type httpDeliveryFixture struct {
|
||||||
|
|||||||
@@ -462,8 +462,7 @@ func TestScheduledRetryIsNotSweptDuringBackoff(t *testing.T) {
|
|||||||
|
|
||||||
// TestRedispatchStampsTheRow pins the cadence control: a stranded
|
// TestRedispatchStampsTheRow pins the cadence control: a stranded
|
||||||
// delivery that has just been handed out is not selected again by the
|
// delivery that has just been handed out is not selected again by the
|
||||||
// next tick a minute later. The stamp is stored in the same form as
|
// next tick a minute later.
|
||||||
// created_at.
|
|
||||||
func TestRedispatchStampsTheRow(t *testing.T) {
|
func TestRedispatchStampsTheRow(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
@@ -494,13 +493,4 @@ func TestRedispatchStampsTheRow(t *testing.T) {
|
|||||||
"a re-dispatched delivery must be stamped so the "+
|
"a re-dispatched delivery must be stamped so the "+
|
||||||
"next tick does not select it again",
|
"next tick does not select it again",
|
||||||
)
|
)
|
||||||
|
|
||||||
var createdAt, updatedAt string
|
|
||||||
|
|
||||||
require.NoError(t, s.WebhookDB.Raw(
|
|
||||||
`SELECT CAST(created_at AS TEXT), CAST(updated_at AS TEXT)
|
|
||||||
FROM deliveries WHERE id = ?`, d.ID,
|
|
||||||
).Row().Scan(&createdAt, &updatedAt))
|
|
||||||
assertStoredTime(t, createdAt)
|
|
||||||
assertStoredTime(t, updatedAt)
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -277,11 +277,7 @@ func (w *archiveWriter) write(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// GORM's clock, the one that stamps created_at in the other
|
row.ArchivedAt = time.Now()
|
||||||
// databases, so this is stored in the same form. A bare time.Now()
|
|
||||||
// carries a monotonic clock reading, which the driver would store
|
|
||||||
// as an " m=+…" suffix.
|
|
||||||
row.ArchivedAt = w.db.NowFunc()
|
|
||||||
|
|
||||||
err := w.db.Create(&row).Error
|
err := w.db.Create(&row).Error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -150,13 +150,6 @@ func TestArchiveWriter_WritesRow(t *testing.T) {
|
|||||||
assert.Equal(t, row.ContentType, got[0].ContentType)
|
assert.Equal(t, row.ContentType, got[0].ContentType)
|
||||||
assert.JSONEq(t, `{"hello":"world"}`, got[0].Body)
|
assert.JSONEq(t, `{"hello":"world"}`, got[0].Body)
|
||||||
assert.False(t, got[0].ArchivedAt.IsZero())
|
assert.False(t, got[0].ArchivedAt.IsZero())
|
||||||
|
|
||||||
var archivedAt string
|
|
||||||
|
|
||||||
require.NoError(t, w.DB().Raw(
|
|
||||||
"SELECT CAST(archived_at AS TEXT) FROM archived_events",
|
|
||||||
).Row().Scan(&archivedAt))
|
|
||||||
assertStoredTime(t, archivedAt)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestArchiveWriter_RecreatesAfterRemoval(
|
func TestArchiveWriter_RecreatesAfterRemoval(
|
||||||
|
|||||||
Reference in New Issue
Block a user