getsentry / sentry-javascript-bundler-plugins

JavaScript Bundler Plugins for Sentry
https://sentry.io
BSD 3-Clause "New" or "Revised" License
141 stars 36 forks source link

esbuild plugin: You are attempting to use this endpoint too frequently #510

Closed drmikecrowe closed 7 months ago

drmikecrowe commented 8 months ago

Environment

package:
  individually: true
  "@sentry/esbuild-plugin": "^2.16.0"
  "@sentry/integrations": "^7.107.0"
  "@sentry/node": "^7.107.0"
  "@sentry/serverless": "^7.88.0"
  "serverless": "^3.38.0"
  "serverless-domain-manager": "^7.3.3"
  "serverless-esbuild": "^1.50.0"
  "serverless-latest-layer-version": "^2.1.2"
  "serverless-offline": "^13.3.2"
  "serverless-plugin-warmup": "^8.3.0"
  "serverless-sentry": "^2.5.3"
  "serverless-sentry-lib": "^2.5.2"
const { sentryEsbuildPlugin } = require('@sentry/esbuild-plugin')
const esbuildPluginTsc = require('esbuild-plugin-tsc')
const { nodeExternalsPlugin } = require('esbuild-node-externals')

module.exports = (serverless) => {
  return {
    entryPoints: [serverless.service.provider.entryFile],
    platform: 'node',
    bundle: true,
    minify: false,
    packages: 'external',
    sourcemap: true,
    keepOutputDirectory: true,
    treeShaking: true,
    resolveExtensions: ['.ts', '.js', '.mjs'],
    logOverride: {
      'import-is-undefined': 'silent',
    },
    loader: {
      '.node': 'copy',
      '.html': 'empty',
    },
    plugins: [
      esbuildPluginTsc({
        tsconfigPath: './tsconfig.eslint.json',
      }),
      sentryEsbuildPlugin({
        org: 'pinnacle-solutions-group',
        project: 'node-' + serverless.variables.service.custom.service.name,
        authToken: process.env.SENTRY_AUTH_TOKEN,
        _experiments: {
          injectBuildInformation: true,
        },
      }),
      nodeExternalsPlugin({
        allowWorkspaces: true,
      }),
    ],
  }
}

Steps to Reproduce

I'm not sure why this is triggering. I'm simply trigging esbuild and have no special build additions other than documented here

Expected Result

This should not trigger any error.

Actual Result

This randomly generates these errors. I repeated the CICD step and it passed w/o any issues.

tnb-api:deploy-dev: "You are attempting to use this endpoint too frequently. Limit is 40 requests in 1 seconds"
tnb-api:deploy-dev: sentry: Received error response from Sentry:
tnb-api:deploy-dev: "You are attempting to use this endpoint too frequently. Limit is 40 requests in 1 seconds"
tnb-api:deploy-dev: sentry: Deploying release "cffdefd"...
tnb-api:deploy-dev: sentry: Received error response from Sentry:
tnb-api:deploy-dev: "You are attempting to use this endpoint too frequently. Limit is 40 requests in 1 seconds"
tnb-api:deploy-dev: 
tnb-api:deploy-dev: × Stack tab-api-dev failed to deploy (295s)
tnb-api:deploy-dev: Environment: linux, node 18.19.1, framework 3.38.0 (local), plugin 7.2.0, SDK 4.5.1
tnb-api:deploy-dev: Credentials: Local, environment variables
tnb-api:deploy-dev: Docs:        docs.serverless.com
tnb-api:deploy-dev: Support:     forum.serverless.com
tnb-api:deploy-dev: Bugs:        github.com/serverless/serverless/issues
tnb-api:deploy-dev: Error:
tnb-api:deploy-dev: 
tnb-api:deploy-dev: Error: Sentry: Error deploying release - Error: Too Many Requests
tnb-api:deploy-dev:     at SentryPlugin.<anonymous> (/builds/pinnsg/internal-apps/.yarn/__virtual__/serverless-sentry-virtual-f5188e84c1/4/root/.yarn/berry/cache/serverless-sentry-npm-2.5.3-fbe9fa9530-10c0.zip/node_modules/serverless-sentry/dist/index.js:652:31)
tnb-api:deploy-dev:     at step (/builds/pinnsg/internal-apps/.yarn/__virtual__/serverless-sentry-virtual-f5188e84c1/4/root/.yarn/berry/cache/serverless-sentry-npm-2.5.3-fbe9fa9530-10c0.zip/node_modules/serverless-sentry/dist/index.js:44:23)
tnb-api:deploy-dev:     at Object.throw (/builds/pinnsg/internal-apps/.yarn/__virtual__/serverless-sentry-virtual-f5188e84c1/4/root/.yarn/berry/cache/serverless-sentry-npm-2.5.3-fbe9fa9530-10c0.zip/node_modules/serverless-sentry/dist/index.js:25:53)
tnb-api:deploy-dev:     at rejected (/builds/pinnsg/internal-apps/.yarn/__virtual__/serverless-sentry-virtual-f5188e84c1/4/root/.yarn/berry/cache/serverless-sentry-npm-2.5.3-fbe9fa9530-10c0.zip/node_modules/serverless-sentry/dist/index.js:17:65)
tnb-api:deploy-dev:     at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
tnb-api:deploy-dev: ERROR: command finished with error: command (/builds/pinnsg/internal-apps/apps/tnb/tnb-api) /tmp/xfs-e36145ed/yarn run deploy-dev exited (1)
tnb-api#deploy-dev: command (/builds/pinnsg/internal-apps/apps/tnb/tnb-api) /tmp/xfs-e36145ed/yarn run deploy-dev exited (1)
lforst commented 8 months ago

I am assuming you are uploading source maps for 87 lambdas in quick succession and you are running into our rate limits. Can you try somehow adding a sleep in between the individual builds as a workaround? 1-2 seconds between each build should probably be enough.

I am not sure whether we will increase the rate limit on our API for this use case as it is a bit special I'd say. If the esbuild plugin doesn't work for your use-case you can also use Sentry CLI.

drmikecrowe commented 8 months ago

Sorry @lforst -- I need you guys to do it. I tried to fork/test, but this project is using an EOL version of node that my OS won't install, and trying to use a local version of node-18 gives errors like this:

sentry-javascript-bundler-plugins  main @ 6fd1363 ∽ 30s ❄️ nix-shell-env❯  yarn build
yarn run v1.22.22
$ nx run-many --target=build --all

    ✖  nx run @sentry/babel-plugin-component-annotate:build
$ rimraf ./out && run-p build:rollup build:types
$ rollup --config rollup.config.js
$ tsc --project types.tsconfig.json

       src/index.ts → dist/esm/index.mjs, dist/cjs/index.js...
       created dist/esm/index.mjs, dist/cjs/index.js in 1.4s
       src/index.ts(136,15): error TS2345: Argument of type 'string | null | undefined' is not assignable to parameter of type 'string | null'.
         Type 'undefined' is not assignable to type 'string | null'.

The fix should be simple, but I can't build/test it. Given this is related to your API limits, can I get some help from you guys to test this? This should be pretty close to what we want:

Replace:

          await upload(buildArtifacts);

with:

          const chunkSize = 35;
          const oneMinute = 60 * 1000; // in milliseconds
          for (let i = 0; i < buildArtifacts.length; i += chunkSize) {
            const currentChunk = buildArtifacts.slice(i, i + chunkSize);
            const timeLeft = oneMinute - (Date.now() % oneMinute);
            await upload(currentChunk);
            const sleepTime = Math.max(0, timeLeft - 50); // add some extra 50ms to account for timing inaccuracies
            await new Promise((resolve) => setTimeout(resolve, sleepTime));
          }

Full code for that function

function esbuildDebugIdUploadPlugin(
  upload: (buildArtifacts: string[]) => Promise<void>
): UnpluginOptions {
  return {
    name: "sentry-esbuild-debug-id-upload-plugin",
    esbuild: {
      setup({ initialOptions, onEnd }) {
        initialOptions.metafile = true;
        onEnd(async (result) => {
          const buildArtifacts = result.metafile ? Object.keys(result.metafile.outputs) : [];
          // sentry API appears to have a rate limit of 40 requests per minute -- chunk and finish in batches
          const chunkSize = 35;
          const oneMinute = 60 * 1000; // in milliseconds
          for (let i = 0; i < buildArtifacts.length; i += chunkSize) {
            const currentChunk = buildArtifacts.slice(i, i + chunkSize);
            const timeLeft = oneMinute - (Date.now() % oneMinute);
            await upload(currentChunk);
            const sleepTime = Math.max(0, timeLeft - 50); // add some extra 50ms to account for timing inaccuracies
            await new Promise((resolve) => setTimeout(resolve, sleepTime));
          }
        });
      },
    },
  };
}
lforst commented 8 months ago

Two things:

drmikecrowe commented 7 months ago

You are right, it won't. Turns out, I had another plugin (serverless-sentry) installed that was duplicating the upload and causing the issue. My bad, sorry for the confusion