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

Worker running into HTTP 429 #68

Closed
tycrek opened this issue Dec 13, 2022 · 12 comments
Closed

Worker running into HTTP 429 #68

tycrek opened this issue Dec 13, 2022 · 12 comments

Comments

@tycrek
Copy link

tycrek commented Dec 13, 2022

I noticed my site is failing to load resources, causing my users to receive an HTTP 500 (generates a pack based off the user skin). What I believe is happening is Crafthead is running into HTTP 429 (Too Many Requests) against the Mojang UUID/Username API.

One possible fix may be to use PlayerDB.co instead of the Mojang API used here

/~https://github.com/astei/crafthead/blob/b00709697fea5f84337aef4bf28e095aed4a94f9/worker/services/mojang/api.ts#L101

It is also sponsored by Nodecraft, same as Crafthead ;)

@tycrek
Copy link
Author

tycrek commented Dec 13, 2022

Agh. Nevermind, a lookup of myself was immediately ratelimited by Mojang through PlayerDB. Very odd.

@andreasdc
Copy link

PlayerDB also returns
{"message":"Mojang has rate limited this request.","code":"minecraft.rate_limited","data":{},"success":false,"error":true}
@astei can you check if your repo doesn't generate too much movement? All cloudflare workers are getting rate limitted since some time.

@astei
Copy link
Collaborator

astei commented Dec 14, 2022 via email

@andreasdc
Copy link

andreasdc commented Dec 14, 2022

Sounds cool, it's good to find new perspectives. Nowadays all workers are getting rate limited from mojang globally at the same time, it was non stop for almost 24 hours, maybe you see bigger movement or something like that.
I heard that on cloudflare you can setup ratelimit too.

@Cherry
Copy link
Member

Cherry commented Jan 2, 2023

We've implemented a solution on PlayerDB that effectively uses some servers outside of Cloudflare to fetch profiles when running into 429s. That might be a good solution here now.

@andreasdc
Copy link

Last time I checked PlayerDB had rate limits too when cloudflare was down.

@Cherry
Copy link
Member

Cherry commented Jan 2, 2023

Last time I checked PlayerDB had rate limits too

Yep, this was a recent change we made before the holidays to workaround the increasing number of 429s we were seeing from Mojang. Outside of rate limits enforced by Mojang, we don't enforce any rate limits ourselves.

@andreasdc
Copy link

What do you mean? I'm saying that PlayerDB was rate limited from mojang when cf was down.

@tycrek
Copy link
Author

tycrek commented Jan 9, 2023

I don't have a full solution, but a potential workaround for users who are able to host outside of Workers, you can directly interface with Mojang's API and with proper caching, should avoid ratelimits. You could probably adapt this to be similar to what Cherry alluded to.

I've adapted my code from my project to a simple skin downloader using Axios and Sharp. Hopefully this helps someone else or at least saves some time:

// axios can easily be replace with fetch or node-fetch
const axios = require('axios');

// image manipulation library. Can be replaced with Jimp if you prefer.
const sharp = require('sharp');

/**
 * Mojang API endpoints
 */
const MOJANG_API = {
    /**
     * Accepts either a username or UUID and returns both from Mojang
     */
    UUID: 'https://api.mojang.com/users/profiles/minecraft/',

    /**
     * Only accepts a UUID. Returns the profile data, containing the URL of the skin
     */
    SKIN: 'https://sessionserver.mojang.com/session/minecraft/profile/'
};

/**
 * Gets a player skin using Mojang API's
 */
const getSkin = (username) => new Promise((resolve, reject) =>
    // Get the UUID from the username
    axios.get(MOJANG_API.UUID.concat(username))
        .then((uuidResponse) => {
            // If code is HTTP 204, username is not valid
            if (uuidResponse.status === 204) throw new Error('Username not found');
            // Get the players profile via the UUID
            return axios.get(MOJANG_API.SKIN.concat(uuidResponse.data.id));
        })
        // Why does Mojank put encoded JSON *inside yet another JSON*? who knows
        .then((profileResponse) => Buffer.from(profileResponse.data.properties[0].value, 'base64').toString('ascii'))
        // Download the actual skin
        .then((buffer) => axios.get(JSON.parse(buffer).textures.SKIN.url, { responseType: 'arraybuffer' }))
        .then((imageResponse) => sharp(Buffer.from(imageResponse.data, 'base64')))
        .then(resolve)
        .catch(reject));

if (process.argv.length < 3) {
    console.log('Please provide a username');
    process.exit(1);
} else getSkin(process.argv[2])
    .then((img) => img.toFile('skin.png'))
    .then(() => console.log('Image saved'))
    .catch(console.error)

If you need to manipulate skins or reconstruct avatars, you can do it with Sharp, it's just a bit of a pain in the ass to figure out and probably adds a ridiculous amount of overhead.

Unfortunately this seems to be the end of the road for this problem, at least until Mojang acknowledges the issue.

@ShayBox
Copy link

ShayBox commented Jan 10, 2023

What's the current cache strategy? I'm getting 429 on stuff that was fetched earlier and should be cached, or at least fallback to cached if the request is rate-limited.

Two strategies I can see:

  1. Keep all profiles cached and only fetch/update on request if it's older than X
  2. Keep all profiles cached and separate fetching/updating into a continuous background task that only fetches the most outdated profiles first and/or prioritizing more requested profiles.

@tycrek
Copy link
Author

tycrek commented Jan 23, 2023

I don't have a direct alternative to Crafthead's utility routes, but I do have an alternative UUID/skin lookup service for Mojang's API: /~https://github.com/tycrek/mulv

I'm hosting it via Vercel Serverless Functions on https://mulv.tycrek.dev but please consider hosting yourself as I'm only on the free tier and need it for my own uses as well.

So far in my testing I haven't hit any HTTP 429 on Mojang's API, but you never know what'll happen.

@mja00
Copy link
Contributor

mja00 commented Jan 25, 2024

This should now be fixed with the latest change. We now go through PlayerDB to grab profile information. Feel free to open up a new issue if you run into issues.

@mja00 mja00 closed this as completed Jan 25, 2024
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

No branches or pull requests

6 participants