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

feat(core): Introduce New Transports API #4716

Merged
merged 9 commits into from
Mar 21, 2022
Merged

Conversation

AbhiPrasad
Copy link
Member

@AbhiPrasad AbhiPrasad commented Mar 14, 2022

Part 1 of #4660
Supercedes #4662

This PR introduces a functional transport based on what was discussed in #4660.

The transport is defined by an interface, which sets two basic functions, send and flush, which both interact directly with an internal PromiseBuffer data structure, a queue of requests that represents the data that needs to be sent to Sentry.

interface NewTransport {
  // If `$` is set, we know that this is a new transport.
  // TODO(v7): Remove this as we will no longer have split between
  // old and new transports.
  $: boolean;
  send(request: Envelope, category: TransportCategory): PromiseLike<TransportResponse>;
  flush(timeout: number): PromiseLike<boolean>;
}

send relies on an externally defined makeRequest function (that is passed into a makeTransport constructor) to make a request, and then return a status based on it. It also updates internal rate-limits according to the response from makeRequest. The status will be also used by the client in the future for client outcomes (we will extract client outcomes from the transport -> client because it living in the transport is not the best pattern).

send takes in an envelope, which means that for now, no errors will go through this transport when we update the client to use this new transport.

flush, flushes the promise buffer, pretty much how it worked before.

To make a custom transport (and how we'll be making fetch, xhr transports), you essentially define a makeRequest function.

function createFetchTransport(options: FetchTransportOptions): NewTransport {
  function makeRequest(request: TransportRequest): PromiseLike<TransportMakeRequestResponse> {
    return fetch(options.url, options.fetchOptions).then(response => {
      return response.text().then(body => ({
        body,
        headers: {
          'x-sentry-rate-limits': response.headers.get('X-Sentry-Rate-Limits'),
          'retry-after': response.headers.get('Retry-After'),
        },
        reason: response.statusText,
        statusCode: response.status,
      }));
    });
  }

  return createTransport({ bufferSize: options.bufferSize }, makeRequest);
}

^^ Look how clean that is!!

Resolves https://getsentry.atlassian.net/browse/WEB-662

@github-actions
Copy link
Contributor

github-actions bot commented Mar 14, 2022

size-limit report

Path Base Size (ebc9da5) Current Size Change
@sentry/browser - ES5 CDN Bundle (gzipped + minified) 19.49 KB 19.49 KB +0.01% 🔺
@sentry/browser - ES5 CDN Bundle (minified) 62.17 KB 62.17 KB 0%
@sentry/browser - ES6 CDN Bundle (gzipped + minified) 18.11 KB 18.12 KB +0.02% 🔺
@sentry/browser - ES6 CDN Bundle (minified) 55.5 KB 55.5 KB 0%
@sentry/browser - Webpack (gzipped + minified) 22.6 KB 22.6 KB 0%
@sentry/browser - Webpack (minified) 79.21 KB 79.21 KB 0%
@sentry/react - Webpack (gzipped + minified) 22.63 KB 22.63 KB 0%
@sentry/nextjs Client - Webpack (gzipped + minified) 47.6 KB 47.6 KB 0%
@sentry/browser + @sentry/tracing - ES5 CDN Bundle (gzipped + minified) 25.36 KB 25.36 KB +0.01% 🔺
@sentry/browser + @sentry/tracing - ES6 CDN Bundle (gzipped + minified) 23.72 KB 23.72 KB +0.01% 🔺

@AbhiPrasad AbhiPrasad force-pushed the abhi-brand-new-transports branch from 58eec6a to a4fc0b3 Compare March 17, 2022 16:49
@AbhiPrasad AbhiPrasad force-pushed the abhi-brand-new-transports branch from a4fc0b3 to f0b49b4 Compare March 17, 2022 16:57
@AbhiPrasad AbhiPrasad marked this pull request as ready for review March 17, 2022 16:58
@kamilogorek kamilogorek self-requested a review March 18, 2022 12:13

export type TransportMakeRequestResponse = {
body?: string;
headers?: Record<string, string | null>;
Copy link
Member Author

Choose a reason for hiding this comment

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

debating if I need to make the rate limiting headers mandatory here.

Copy link
Member

Choose a reason for hiding this comment

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

When I read through the PR I instinctively asked myself the same thing. In my very uneducated opinion it should be non-optional.

Also: Is there a reason we allow null?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah I will change this to be non-optional

We allow null because most getters for headers return null if not defined. For example, https://developer.mozilla.org/en-US/docs/Web/API/Headers/get

Copy link
Member

@Lms24 Lms24 left a comment

Choose a reason for hiding this comment

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

This is looking good as far as I can tell. Checked out the branch and ran the tests. I just left a comment on the rate limit tests. Although, with our conversation from earlier in mind, feel free to ignore it if you want.

Comment on lines 108 to 111
const retryAfterSeconds = 10;
const beforeLimit = Date.now();
const withinLimit = beforeLimit + (retryAfterSeconds / 2) * 1000;
const afterLimit = beforeLimit + retryAfterSeconds * 1000;
Copy link
Member

Choose a reason for hiding this comment

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

Just a suggestion: Since these variables are identical in 5 tests, I think it would make sense to extract them into a helper function.

Copy link
Member Author

Choose a reason for hiding this comment

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

Extracted!

Copy link
Member

@lforst lforst left a comment

Choose a reason for hiding this comment

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

I really like the API - super clean! I left some comments on naming and a potential small bug (?). The tests also look great.


export type TransportMakeRequestResponse = {
body?: string;
headers?: Record<string, string | null>;
Copy link
Member

Choose a reason for hiding this comment

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

When I read through the PR I instinctively asked myself the same thing. In my very uneducated opinion it should be non-optional.

Also: Is there a reason we allow null?

packages/core/src/transports/base.ts Show resolved Hide resolved
packages/core/src/transports/base.ts Show resolved Hide resolved
packages/core/src/transports/base.ts Outdated Show resolved Hide resolved
packages/core/src/transports/base.ts Show resolved Hide resolved
packages/core/src/transports/base.ts Outdated Show resolved Hide resolved
packages/core/src/transports/base.ts Outdated Show resolved Hide resolved
@AbhiPrasad
Copy link
Member Author

In the spirit of moving fast, I'm going to merge this in and start work on the client side stuff. We can make improvements to this later on.

@AbhiPrasad AbhiPrasad merged commit 76acf2f into master Mar 21, 2022
@AbhiPrasad AbhiPrasad deleted the abhi-brand-new-transports branch March 21, 2022 16:02
@AbhiPrasad AbhiPrasad added this to the Pre 7.0.0 Work milestone Mar 23, 2022
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.

3 participants