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

fix: Fixing email sending broken when attempting to send emails from different goroutines due to a data race #494

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

andrew-pavlov-ua
Copy link

Fixes

When trying to send several emails at the same time, the emails are not sent because the client uses a shared built-in field rest.Request, which is overwritten by different goroutines.

// Client is the Twilio SendGrid Go client
type Client struct {
	rest.Request
}
// SendWithContext sends an email through Twilio SendGrid with context.Context
func (cl *Client) SendWithContext(ctx context.Context, email *mail.SGMailV3) (*rest.Response, error) {
	cl.Request.Body = mail.GetRequestBody(email)

	// ...
}

Here is a test I wrote to show this:

func Test_test_client_send_is_thread_safe(t *testing.T) {
	apiKey := "SENDGIRD_APIKEY"
	const numRequests = 5
	var wg sync.WaitGroup
	client := NewSendClient(apiKey)

	// Launch multiple goroutines to send concurrent requests
	for i := 0; i < numRequests; i++ {
		wg.Add(1)
		go func(i int) {
			defer wg.Done()
			from := &mail.Email{
				Name:    "Name",
				Address: "[email protected]",
			}

			to := &mail.Email{
				Name:    "Recipient",
				Address: "[email protected]",
			}

			email := &mail.SGMailV3{
				From: from,
				Personalizations: []*mail.Personalization{
					{
						To:      []*mail.Email{to},
						Subject: "Subject",
					},
				},
				Content: []*mail.Content{
					{
						Type:  "text/plain",
						Value: "Value",
					},
				},
			}

			client.Send(email)
		}(i)
	}
	wg.Wait()
}

Started the test using the following command:

go test ./... -v -run=Test_test_client_send_is_thread_safe -race

Here is the console output after running the test before applying my fixes:

testing.go:1399: race detected during execution of test
--- FAIL: Test_test_client_send_is_thread_safe (0.83s)

After my fixes, the test passes, emails are successfully sent, and the client is now thread-safe.

I replaced the embedded Request in Client with two private fields: apiKey and emailOptions. When creating a client, either apiKey or Username and Password are required.

New Implementation:

// Client is the Twilio SendGrid Go client
type Client struct {
	apiKey       string
	emailOptions TwilioEmailOptions
}

I also created the SendWithHeaders method to support additional headers (used in testing). Additionally, I refactored the client creation methods (NewSendClient and NewTwilioEmailSendClient) accordingly.

NewApiKeySendClient:

// NewSendClient constructs a new Twilio SendGrid client given an API key
func NewSendClient(key string) *Client {
	return &Client{apiKey: key}
}

NewEmailSendClient:

// NewTwilioEmailSendClient constructs a new Twilio Email client given a username and password
func NewTwilioEmailSendClient(username, password string) *Client {
	emailOptions := &TwilioEmailOptions{Username: username, Password: password, Endpoint: "/v3/mail/send"}
	return &Client{emailOptions: *emailOptions}
}

Checklist

  • I acknowledge that all my contributions will be made under the project's license
  • I have made a material change to the repo (functionality, testing, spelling, grammar)
  • I have read the Contribution Guidelines and my PR follows them
  • I have titled the PR appropriately
  • I have updated my branch with the main branch
  • I have added tests that prove my fix is effective or that my feature works
  • I have added the necessary documentation about the functionality in the appropriate .md file
  • I have added inline documentation to the code I modified

@andrew-pavlov-ua andrew-pavlov-ua changed the title Fixing email sending broken when attempting to send emails from different goroutines due to a data race fix: Fixing email sending broken when attempting to send emails from different goroutines due to a data race Feb 11, 2025
@YaroslavPodorvanov
Copy link

This PR will fix #474

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.

2 participants