@jmohr1
The Canvas API uses throttling and it depends on the nature of the request and how busy the server is at the time. Don't rely on ~58 as that may change from time to time. You start with 700 for the x-rate-limit-remaining and when it gets to 0, all other requests fail. It used to be that browsers would only allow about 5 requests at a time, but once that ceased to be a restriction, the bombarding the Canvas servers and relying on the browser to throttle stopped working.
I use the bottleneck library for JavaScript to rate limit the requests. I had to modify my script to obtain the access report for an entire course to do threading. Without a library, you can make the requests in series rather than in parallel. I use promises with fetch() rather than jQuery, so I could do a let p = firstCall(); then in a loop, I use p = p.then(nextCall); With bottleneck, I get to use const p = []; Then in a loop, I p.push(apiCall); and return with Promise.all(p);
I guess you could put them in batches of say 10 or 20 with a Promise.all(), wait for that to finish, and then start the next batch. It's all very sensitive to the request you're making. 20 might work for one type of request but not another.
The cheapest, fastest to implement solution may be to use the Chrome Developer Tools and enable throttling there. If you open the developer tools (F12) and go to the Network tab, there is throttling at the top. Originally, it says "No throttling". You could change it to fast 3g and it might slow it down enough that you don't have to incorporate throttling into the code itself. The fast 3g is supposed to introduce 562.5 ms of request latency, which should slow it down to ~2 requests per second and that will give the bucket time to replenish. You could probably create a custom throttling of 100 ms of request latency (10 requests per second) and have it still work. The most important thing is not bombarding it all at the same time. If you stagger the requests, you get more benefit than the number of pending requests. Sending 100 requests by spacing them 1 request every 50 ms is going to have a higher chance of success than sending 100 requests in batches of 20 and spacing them 1 second apart.
I did not test that enabling throttling in the developer tools works as I did not have a browser script handy that I could use.
I did some testing with bottleneck library and a relatively cheap request of fetching a page. I had 183 pages in a course and fetching the list (4 requests of 50 each) and then fetching the 183 pages took 44 seconds if I do them one at a time, waiting for each one to finish. Limiting it to 10 simultaneous requests with a 100 ms delay between each took 19.792 seconds and the x-rate-limit-remaining only dropped to 686 (from 700). Changing the minimum time between requests to 10 ms dropped my limit to 596 but finish in 5.327 s. Then I allowed 20 requests at 10 ms each and the limit dropped to 528 while taking 3.772 s. With 100 connections but 1 ms apart, the limit dropped to 407 and it only took 2.824 seconds. This is where my request may be a bad one because I tried to push it -- 200 maximum connections with 0 delay and it still didn't throw an error. Maybe it's caching or perhaps I've reached the limit of my connection (using wireless a 2016 laptop with a maximum of 200 Mbps).
The point being that the x-rate-limit-remaining varies by request and server load (enrollments are really expensive) and that it's better to stagger the requests -- even by a few ms -- than to batch the requests and wait until one batch is finished before starting the other.
A third route is to talk to the people with the SIS import capability Have them send an enrollments.csv file that turns on the limit_section_privileges for your classes. Perhaps you could create the enrollments.csv file for just your students and have them manually upload it if you don't have admin privileges.