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

notification: store webhook and webhook delivery #413

Merged
merged 1 commit into from
Aug 10, 2023

Conversation

alessandro-sorint
Copy link
Contributor

@alessandro-sorint alessandro-sorint commented Jul 3, 2023

fix #417

@alessandro-sorint alessandro-sorint force-pushed the last-event branch 6 times, most recently from 1a7883b to a76f6e1 Compare July 10, 2023 13:23
@alessandro-sorint alessandro-sorint changed the title add ability to save run webhooks and update status delivery add retry logic for webhook delivery Jul 10, 2023
@alessandro-sorint
Copy link
Contributor Author

@sgotti can you do the review please?

internal/services/notification/runwebhookdeliveryevents.go Outdated Show resolved Hide resolved
internal/services/notification/runwebhookdeliveryevents.go Outdated Show resolved Hide resolved
internal/services/notification/runwebhookdeliveryevents.go Outdated Show resolved Hide resolved
internal/services/notification/runwebhookdeliveryevents.go Outdated Show resolved Hide resolved
internal/services/notification/db/objects/objects.go Outdated Show resolved Hide resolved
Comment on lines 156 to 162
switch runWebhook.PayloadVersion {
case 1:
if err = json.Unmarshal([]byte(runWebhook.Payload), &webhook); err != nil {
return sequence, errors.WithStack(err)
}
default:
return sequence, errors.Errorf("unknown payload version: %d", runWebhook.PayloadVersion)
Copy link
Member

Choose a reason for hiding this comment

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

Why are you unmarshalling the payload?

internal/services/notification/runwebhooksheduler.go Outdated Show resolved Hide resolved
internal/services/notification/runwebhooksheduler.go Outdated Show resolved Hide resolved
internal/services/notification/runwebhookdeliverys.go Outdated Show resolved Hide resolved

err := n.d.Do(ctx, func(tx *sql.Tx) error {
// start from last event
runWebhookDelivery, err := n.d.GetLastRunWebhookDelivery(tx)
Copy link
Member

Choose a reason for hiding this comment

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

Why are you starting from the last sequence? What happens if previous deliveries haven't been handled?

@alessandro-sorint alessandro-sorint force-pushed the last-event branch 2 times, most recently from ce21951 to ce4203d Compare August 2, 2023 07:31
@alessandro-sorint alessandro-sorint changed the title add retry logic for webhook delivery adds saving of webhooks and delivery Aug 2, 2023
@alessandro-sorint alessandro-sorint changed the title adds saving of webhooks and delivery add saving of webhooks and delivery Aug 2, 2023
@alessandro-sorint alessandro-sorint force-pushed the last-event branch 2 times, most recently from dc68b82 to 02695bd Compare August 3, 2023 07:09
internal/services/notification/runwebhookdeliverys.go Outdated Show resolved Hide resolved
internal/services/notification/runwebhookdeliverys.go Outdated Show resolved Hide resolved
Comment on lines 13 to 15
NotDelivered DeliveryStatus = "not_delivered"
Delivered DeliveryStatus = "delivered"
DeliveryError DeliveryStatus = "delivery_error"
Copy link
Member

Choose a reason for hiding this comment

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

DeliveryStatusNotDelivered   DeliveryStatus = "notDelivered"
DeliveryStatusDelivered      DeliveryStatus = "delivered"
DeliveryStatusDeliveryError  DeliveryStatus = "deliveryError"

@@ -0,0 +1,127 @@
// Copyright 2023 Sorint.lab
Copy link
Member

Choose a reason for hiding this comment

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

no camel case in file names...


t.Logf("starting webhooks client")

time.Sleep(1 * time.Second)
Copy link
Member

Choose a reason for hiding this comment

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

This sleep is bad.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I added sleep because the test was failing. I thought the webhookreceiver was not started and needed much time.
I try to remove

Copy link
Member

Choose a reason for hiding this comment

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

webhookreceiver should start and return after is has been started.


if n.c.WebhookSecret != "" {
sig256 := hmac.New(sha256.New, []byte(n.c.WebhookSecret))
_, err = io.MultiWriter(sig256).Write(data)
Copy link
Member

Choose a reason for hiding this comment

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

why io.multiwriter?

@alessandro-sorint alessandro-sorint force-pushed the last-event branch 2 times, most recently from bebb0ac to e5f9b94 Compare August 3, 2023 09:29
sig256 := hmac.New(sha256.New, []byte(n.c.WebhookSecret))
_, err = io.MultiWriter(sig256).Write([]byte(body))
if err != nil {
if err := n.d.InsertOrUpdateRunWebhookDelivery(tx, runWebhookDelivery); err != nil {
Copy link
Member

Choose a reason for hiding this comment

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

Isn't this just an insert?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@sgotti I do not know what you mean

Copy link
Member

Choose a reason for hiding this comment

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

Here you're inserting a new entry, not updating an existing one. So use InsertBla and not InsertOrUpdateBla.

wh = types.NewRunWebhook(tx)
wh.Payload = "payloadtest"

if err := ns.d.InsertOrUpdateRunWebhook(tx, wh); err != nil {
Copy link
Member

Choose a reason for hiding this comment

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

Isn't this just an insert?

wd.DeliveryStatus = deliveryStatus
wd.RunWebhookID = runWebhookID

if err := ns.d.InsertOrUpdateRunWebhookDelivery(tx, wd); err != nil {
Copy link
Member

Choose a reason for hiding this comment

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

Isn't this just an insert?

runWebhookDelivery.Status = status
runWebhookDelivery.StatusCode = statusCode

if err = n.d.InsertOrUpdateRunWebhookDelivery(tx, runWebhookDelivery); err != nil {
Copy link
Member

Choose a reason for hiding this comment

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

Isn't this just an update?

if err != nil {
return errors.WithStack(err)
}
if err := n.d.InsertOrUpdateRunWebhook(tx, wh); err != nil {
Copy link
Member

Choose a reason for hiding this comment

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

Isn't this just an insert?

@@ -0,0 +1,198 @@
// Copyright 2023 Sorint.lab
Copy link
Member

Choose a reason for hiding this comment

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

runwebhookdelivery.go

)

const (
MaxRunWebhookDeliverysLimit = 40
Copy link
Member

Choose a reason for hiding this comment

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

If you want to use the plural form it's deliveries

func (d *DB) GetRunWebhookDeliveryByID(tx *sql.Tx, runWebhookDeliveryID string) (*types.RunWebhookDelivery, error) {
q := runWebhookDeliverySelect()
q.Where(q.E("id", runWebhookDeliveryID))
runWebhookDeliverys, _, err := d.fetchRunWebhookDeliverys(tx, q)
Copy link
Member

Choose a reason for hiding this comment

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

the generated functions could have the wrong plural forms (since it only adds an s) but the manually typed code should use the right plural form (deliveries)

internal/services/notification/notification_test.go Outdated Show resolved Hide resolved

if n.c.WebhookSecret != "" {
sig256 := hmac.New(sha256.New, []byte(n.c.WebhookSecret))
_, err = io.WriteString(sig256, webhookPayload)
Copy link
Member

Choose a reason for hiding this comment

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

Use h256.Write ?

internal/services/notification/runwebhookdelivery.go Outdated Show resolved Hide resolved
@sgotti sgotti changed the title add saving of webhooks and delivery notification: store webhook and delivery Aug 3, 2023

func (d *DB) GetRunWebhookDeliveriesNotDeliveredAfterSequence(tx *sql.Tx, afterSequence uint64, limit int) ([]*types.RunWebhookDelivery, error) {
q := runWebhookDeliverySelect().OrderBy("sequence").Asc()
q.Where(q.E("delivery_status", types.DeliveryStatusNotDelivered))
Copy link
Member

Choose a reason for hiding this comment

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

This, in previous commits, was a query option to filter by delivery_status. Why was it removed and made fixed?

return s[0], nil
}

func (d *DB) GetRunWebhookDeliveries(tx *sql.Tx, limit int) ([]*types.RunWebhookDelivery, error) {
Copy link
Member

Choose a reason for hiding this comment

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

This isn't really useful. It's used only by tests, you could use just a single functions with an optional filter on status, startSequence and limit. See also next comment.

t.Logf("starting webhooks client")

ns.c.WebhookURL = fmt.Sprintf("%s/%s", wr.exposedURL, "webhooks")
ns.c.WebhookSecret = "secretkey"
Copy link
Member

Choose a reason for hiding this comment

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

use a const

t.Fatalf("expected %s run webhook payload got: %s", runWebhooks[i].Payload, webhooks[i].payload)
}

h256 := hmac.New(sha256.New, []byte(ns.c.WebhookSecret))
Copy link
Member

Choose a reason for hiding this comment

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

use a const var, not ns.c.WebhookSecret

type RunWebhook struct {
sqlg.ObjectMeta

Payload string `json:"payload,omitempty"`
Copy link
Member

Choose a reason for hiding this comment

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

no omitempty

type RunWebhookDelivery struct {
sqlg.ObjectMeta

Sequence uint64
Copy link
Member

Choose a reason for hiding this comment

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

missing json tags

internal/services/notification/db/objects/objects.go Outdated Show resolved Hide resolved
type RunWebhook struct {
sqlg.ObjectMeta

Payload string `json:"payload,omitempty"`
Copy link
Member

Choose a reason for hiding this comment

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

[]byte

}

type webhook struct {
payload string
Copy link
Member

Choose a reason for hiding this comment

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

[]byte

{Name: "DeliveryStatus", Type: "types.DeliveryStatus", BaseType: "string"},
{Name: "DeliveredAt", Type: "time.Time", Nullable: true},
{Name: "Duration", Type: "time.Duration", Nullable: true},
{Name: "Status", Type: "string"},
Copy link
Member

Choose a reason for hiding this comment

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

Is Status really needed? Isn't StatusCode enough?

{Name: "RunWebhookID", Type: "string"},
{Name: "DeliveryStatus", Type: "types.DeliveryStatus", BaseType: "string"},
{Name: "DeliveredAt", Type: "time.Time", Nullable: true},
{Name: "Duration", Type: "time.Duration", Nullable: true},
Copy link
Member

Choose a reason for hiding this comment

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

Duration is not really needed.

}

func (n *NotificationService) sendRunWebhook(ctx context.Context, webhookPayload []byte, runWebhookUUID string) (*http.Response, *time.Duration, error) {
c := &http.Client{}
Copy link
Member

Choose a reason for hiding this comment

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

Why a new empty http client?

Copy link
Member

Choose a reason for hiding this comment

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

This should contain some data for TestCreate.

Copy link
Member

Choose a reason for hiding this comment

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

This file is not related to this PR.

}
}

func (n *NotificationService) handleRunWebhookDelivery(ctx context.Context, runWebhookDelivery *types.RunWebhookDelivery) error {
Copy link
Member

Choose a reason for hiding this comment

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

pass runWebhookDeliveryID

}

if runWebhookDelivery.DeliveryStatus != types.DeliveryStatusNotDelivered {
return errors.Errorf("run webhook delivery %q already delivered", runWebhookDeliveryID)
Copy link
Member

Choose a reason for hiding this comment

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

No need to error, just return

return errors.WithStack(err)
}
if runWebhookDelivery.DeliveryStatus != types.DeliveryStatusNotDelivered {
return errors.Errorf("run webhook delivery %q already delivered", runWebhookDeliveryID)
Copy link
Member

Choose a reason for hiding this comment

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

No need to error, just return.

internal/services/notification/webhooksreceiver.go Outdated Show resolved Hide resolved
@sgotti sgotti changed the title notification: store webhook and delivery notification: store webhook and webhook delivery Aug 9, 2023
Copy link
Member

@sgotti sgotti left a comment

Choose a reason for hiding this comment

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

Please fix the commit title (as the PR title that I have updated) and description (why notification: at every line?).

add db schema
add RunWebhook and RunWebhookDelivery type
add header X-Agola-Delivery when send run webhooks
@alessandro-sorint
Copy link
Contributor Author

Please fix the commit title (as the PR title that I have updated) and description (why notification: at every line?).

@sgotti I fixed the commit

@sgotti sgotti merged commit 7d3f59c into agola-io:master Aug 10, 2023
1 check passed
@alessandro-sorint alessandro-sorint deleted the last-event branch November 20, 2023 08:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

notification service: save webhook and deliverys
2 participants