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

Pymongo trace tcp connections #1455

Merged
merged 5 commits into from
Aug 28, 2020

Conversation

LetzNico
Copy link
Contributor

cf. #1442

@LetzNico LetzNico force-pushed the pymongo-trace-tcp-connections branch from 8867e90 to 8a02aa3 Compare May 23, 2020 19:36
Copy link
Member

@Kyle-Verhoog Kyle-Verhoog left a comment

Choose a reason for hiding this comment

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

Looks great after a first pass! Just need a few tests to confirm.

To address your questions from the issue thread:

What could be a good approach to test the new trace?

What we typically do is we replace the default tracer instance with our own dummy tracer which will capture all the spans so that we can access them for testing. Looking at the pymongo test suite it's a bit of a mess... I'd recommend to create a separate test case class in tests/contrib/pymongo/test.py starting with something like:

class TestPymongoPool(BaseTracerTestCase):
    def setUp(self):
        patch()
        self.tracer = get_dummy_tracer()
        Pin.override(pymongo.pool.Pool, tracer=self.tracer)

    def tearDown(self):
        unpatch()

    def test_pool(self):
        # do a pool operation which will generate traces
        spans = self.tracer.writer.pop()
        # assert on the spans

Are the tags correct?

They look good to me after a first pass. Will look closer on the next pass :)

Is the way I instanciate the pin correct to?

Yep this looks good to me!

To make the old tests pass, I'm considering dropping from the spans retrieved by the writer all "tcp connect" spans. That would mean, for example, adding a list comprehension like spans = [span for span in spans if span.name in ("mongo_op", "pymongo.cmd")] after this line. Do you think it is a good idea? If not, can you recommend me another approach?

Hmm yeah I was thinking about that as I was going through the test suite. Yes, I think this is a good approach as any to get around the design of the current tests. (As an aside we should certainly rewrite the test suite for pymongo as part of the rewrite 😛)

@LetzNico LetzNico force-pushed the pymongo-trace-tcp-connections branch from c2fd372 to 25884ec Compare June 10, 2020 12:37
@LetzNico
Copy link
Contributor Author

Hey!

Sorry I have not taken the time lately to continue working on that PR. Thanks a lot for your review @Kyle-Verhoog, it has been very helpful.

The PR is pretty much ready, I've just been stuck on a problem. I'm leaving a comment on the PR. If you could help me once again, that would be greatly appreciated!


def traced_pool_connect(wrapped, instance, args, kwargs):
pin = Pin._find(wrapped, instance)
is_monitoring_pool = instance.opts.connect_timeout == instance.opts.socket_timeout
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I have discovered that pymongo maintains a background monitoring pool.

The thing is that since we patch a function in the pool class, we get traces from both the monitoring pool (created here) and the active pool (created here) while we only want to retrieve traces from the active pool.

I think we can workaround the problem by performing a check on the instance. For the sake of the example, I've used an implementation detail on the timeout of the pool sockets to detect which pool emitted the span but that is definitely not satisfying.
Do you have an idea to detect which pool is emitting the span? Would patching pymongo's _create_pool_for_server and _create_pool_for_monitor to add an hidden attribute to the pool be an acceptable solution?

Copy link
Member

Choose a reason for hiding this comment

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

Hey! Sorry for the long delay. Hmmm interesting. After looking at the examples (thanks for the code references!) it does seem like patching _create_pool_for_server would make sense. IMO it'd be better if we're able to avoid patching the undesired path entirely. Is it relatively easy to accomplish?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

No worries :) Once again, thanks for your time @Kyle-Verhoog

IMO it'd be better if we're able to avoid patching the undesired path entirely. Is it relatively easy to accomplish?

Agree with you but tbh I have not found a way to do it :/ Basically in pseudo-python, the flow is like this:

class PyMongoClient:
    def __init__(self, ip, port):
        self.ip = ip
        self.port = port
        # This runs in a separate thread
        self.start_monitoring()

    def start_monitoring(self):
        while True:
            for monitor in self.monitors:
                monitor.get_socket(self.ip, self.port) as sock_info:
            	    sock_info.health_check()
                time.sleep(x)

    def run_cmd(self, cmd):
        server = self.servers[(self.ip, self.port)]
        with server.get_socket(self.ip, self.port) as sock_info:
            sock_info.send(cmd)

class Server:
    def get_socket(self):
        return self.pool.get_socket()

class Monitor:
    def get_socket(self);
        return self.pool.get_socket()

class Pool:
    def get_socket(self):
        # (...)
        try:
            # Lookup of an already existing, ready socket. This call does not take time
            socket = self.sockets.popleft()
        except IndexError:
            # Creation of a new socket+handshake. This call does take time
            socket = self.connect()
        return socket

So basically:

  • If we patch pymongo.server.Server's get_socket, we actually trace both Pool's self.sockets.popleft() and Pool's self.connect(). The second one is effectively what we are trying to trace while the first one is not a network call but a lookup in memory which we do not want to trace (I think?)
  • If we patch pymongo.pool.Pool's self.connect(), we only trace actual network calls but we trace network calls of both the Monitor object and the Server object. That means that we generate traces for both the pymongo thread that handle incoming requests (good) but also from the pymongo thread that performs monitoring health_checks on the remote address (bad)

I do not see a way to only patch the critical path, unfortunately :( That leaves us with 2 viable options imo:

  • Trace pymongo.pool.Pool's get_socket: it will generate tiny traces when the socket already exists and classic traces when the socket needs to be created
  • Do the hack which adds an hidden attribute pool instances that belong to Servers: it will generate traces only for actual network calls linked to pymongo direct requests but well, it's a bit of a hack

Copy link
Member

Choose a reason for hiding this comment

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

Thanks for that write-up! It's actually really helpful as I'd forgotten some of the context 🙂.

So I'm okay with patching get_socket in general even if there's the chance that it's a quick memory look up. It's meaningful sometimes which is enough reason IMO and our overhead shouldn't be too bad (unless this is done a crazy amount of times). I think we should avoid instrumenting the health checks from Monitor.

Trace pymongo.pool.Pool's get_socket: it will generate tiny traces when the socket already exists and classic traces when the socket needs to be created

Did you mean Server.get_socket here? Else we'd still be getting the health checks? If you did mean Server.get_socket I think that sounds like the way to go 👍. What do you think?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Did you mean Server.get_socket here?

Yep my bad, messed things up! Alright I'm changing the code to patch Server.get_socket :). I'll update you when it's done!

Copy link
Member

Choose a reason for hiding this comment

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

Haha no problem. And great! I'm excited to get this merged 😄

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hmm I've ran into a problem implementing that. Actually Pool's get_socket's code creates&connects the socket and then yields it, making Server's get_socket's a generator. Thus, we cannot trace it effectively with wrap_function_wrapper since generator functions instantly return a generator and the actual code is executed when the parent function decides to consume it.

I believe a workaround could be to consume the socket from the generator in our patch and then yield the socket but I don't think it is a good idea. Are there some wrappers to work with generators in ddtrace?

Copy link
Member

Choose a reason for hiding this comment

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

Agh, I see. Hmm we don't have any utils for patching generators unfortunately. I think we're okay to intercept the generator and yield the socket ourselves as you described. We just unfortunately can't make use of yield from to maintain compatibility with Python 2.

What are your thoughts?

@LetzNico LetzNico force-pushed the pymongo-trace-tcp-connections branch 3 times, most recently from d921dd6 to e705192 Compare June 11, 2020 09:41
Copy link
Member

@Kyle-Verhoog Kyle-Verhoog left a comment

Choose a reason for hiding this comment

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

Nice 👍! I think once the monitor pool issue is figured out I think we're good to go 🙂

@Kyle-Verhoog Kyle-Verhoog marked this pull request as ready for review June 30, 2020 03:37
@Kyle-Verhoog Kyle-Verhoog requested a review from a team as a code owner June 30, 2020 03:37
@LetzNico LetzNico force-pushed the pymongo-trace-tcp-connections branch 3 times, most recently from 49a3b73 to 73b9674 Compare July 14, 2020 17:35
@LetzNico
Copy link
Contributor Author

LetzNico commented Jul 14, 2020

Hey there @Kyle-Verhoog ! I've finally taken the time to finish this PR, sorry for the delay!

Do you mind having a final look? Also, it looks like profile tests are flaky: https://app.circleci.com/pipelines/github/DataDog/dd-trace-py/1818/workflows/5bf2b1c6-52f2-45b1-a39c-5bc0adb8bb46/jobs/291047/steps. Unfortunately it seems like I lack the rights to relaunch those, so the CI won't pass. Do you mind doing it for me 🙏 ? Also, do you want me to create an issue regarding that matter?

@LetzNico LetzNico changed the title Pymongo trace tcp connections (wip) Pymongo trace tcp connections Jul 14, 2020
Copy link
Member

@Kyle-Verhoog Kyle-Verhoog left a comment

Choose a reason for hiding this comment

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

Sweet! I think it's ready in terms of the integration. I think it'd be good to have a few tests (we can use the ones you've already written) checking that the functionality of pymongo is maintained.

Also feel free to format the files with black since we're starting to do that across the project 😄

ddtrace/contrib/pymongo/patch.py Show resolved Hide resolved
tests/contrib/pymongo/test.py Show resolved Hide resolved
@LetzNico LetzNico force-pushed the pymongo-trace-tcp-connections branch from 73b9674 to 89ae97e Compare July 15, 2020 07:31
@LetzNico
Copy link
Contributor Author

Regarding black, I guess I'm lucky that nothing has to be done (I think? I'm not 100% sure about the cmds I used)

# tox -e black tests/contrib/pymongo/
black installed: appdirs==1.4.4,attrs==19.3.0,black==19.10b0,click==7.1.2,pathspec==0.8.0,regex==2020.7.14,toml==0.10.1,typed-ast==1.4.1
black run-test-pre: PYTHONHASHSEED='1888914511'
black run-test: commands[0] | black --check .
All done! ✨ 🍰 ✨
219 files would be left unchanged.
__________________________________________ summary ___________________________________________
  black: commands succeeded
  congratulations :)
# tox -e black ddtrace/contrib/pymongo/
black installed: appdirs==1.4.4,attrs==19.3.0,black==19.10b0,click==7.1.2,pathspec==0.8.0,regex==2020.7.14,toml==0.10.1,typed-ast==1.4.1
black run-test-pre: PYTHONHASHSEED='1678242913'
black run-test: commands[0] | black --check .
All done! ✨ 🍰 ✨
219 files would be left unchanged.
__________________________________________ summary ___________________________________________
  black: commands succeeded
  congratulations :)

@Kyle-Verhoog
Copy link
Member

Kyle-Verhoog commented Jul 15, 2020

@LetzNico oh right. pymongo is probably on the ignore list in pyproject.toml. The change might be better suited for the entire integration refactor, up to you if you still want to do it 😄

@LetzNico LetzNico force-pushed the pymongo-trace-tcp-connections branch 2 times, most recently from a5ee81d to a2ade67 Compare August 14, 2020 10:08
It seems more logical to put it in the patch file rather than in the
client file
* Closes DataDog#1442. This should trace all calls to Server.get_socket(). This
  is useful because for each pymongo cmd, the lib first retrieves a
connected socket and then executes the cmd. Getting a connected socket
takes time when it is not picked from the cache, hence it should be a
good idea to trace that operation. Note that this change does not apply
to the soon-to-be deprecated `trace_mongo_client`.
* Introduces module patching (using ddtrace.vendor.wrapt) to pymongo
  contrib. In time, the old TracedMongoClient should be replaced by
module patchs only.
@LetzNico LetzNico force-pushed the pymongo-trace-tcp-connections branch from a2ade67 to e0a35b3 Compare August 16, 2020 17:54
@LetzNico
Copy link
Contributor Author

Hey there @Kyle-Verhoog ! I finally took some time to wrap up this PR. Excited to hear back from you and hope it will get merged! 🙌

@Kyle-Verhoog
Copy link
Member

hey @LetzNico! Thanks for getting back around to it! I was out on vacation last week but definitely gonna take a look at this, this week once I get caught back up 😄

Copy link
Member

@Kyle-Verhoog Kyle-Verhoog left a comment

Choose a reason for hiding this comment

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

🎉 @LetzNico thanks for seeing this to the finish line!! 😄

@Kyle-Verhoog Kyle-Verhoog added this to the 0.42.0 milestone Aug 28, 2020
@Kyle-Verhoog Kyle-Verhoog merged commit 20ca41b into DataDog:master Aug 28, 2020
@LetzNico
Copy link
Contributor Author

Yeeey! Thanks for your time! Please hit me up in the future for support regarding this feature or if I can be of any help on related topics :)

majorgreys pushed a commit that referenced this pull request Sep 10, 2020
* pymongo: move old trace_mongo_client to patch.py

It seems more logical to put it in the patch file rather than in the
client file

* pymongo: trace Server.get_socket()

* Closes #1442. This should trace all calls to Server.get_socket(). This
  is useful because for each pymongo cmd, the lib first retrieves a
connected socket and then executes the cmd. Getting a connected socket
takes time when it is not picked from the cache, hence it should be a
good idea to trace that operation. Note that this change does not apply
to the soon-to-be deprecated `trace_mongo_client`.
* Introduces module patching (using ddtrace.vendor.wrapt) to pymongo
  contrib. In time, the old TracedMongoClient should be replaced by
module patchs only.

* pymongo: reference #1501

Co-authored-by: Kyle Verhoog <kyle@verhoog.ca>
brettlangdon added a commit that referenced this pull request Jul 24, 2023
This fix introduces a few changes to improve overall CircleCI job
runtime.

**Before:**
- Runtime: 28+ minutes
- Credits: 33k

**After:**
- Runtime: ~22 minutes (-20%)
- Credits: ~15k (-55%)

### Fix mysql test pattern

The `mysql` CircleCI job was using the pattern "mysql", which would also
match the `mysqldb` jobs.

This change updates the test pattern for all mysql jobs to include an
ending `$`.


<details>
<summary>Before</summary>

```
❯ riot list mysql
 No.    Hash     Name     Interpreter                Environment                                               Packages
 #554   1a1c1fa  mysql    Interpreter(_hint='2.7')   DD_TESTING_RAISE=1 DD_REMOTE_CONFIGURATION_ENABLED=false  'mock' 'pytest' 'pytest-mock' 'coverage' 'pytest-cov' 'opentracing'
                                                                                                               'hypothesis<6.45.1' 'mysql-connector-python==8.0.5'
 #555   8ba1245  mysql    Interpreter(_hint='2.7')   DD_TESTING_RAISE=1 DD_REMOTE_CONFIGURATION_ENABLED=false  'mock' 'pytest' 'pytest-mock' 'coverage' 'pytest-cov' 'opentracing'
                                                                                                               'hypothesis<6.45.1' 'mysql-connector-python==8.0.23'
 #556   1e72d9c  mysql    Interpreter(_hint='3.5')   DD_TESTING_RAISE=1 DD_REMOTE_CONFIGURATION_ENABLED=false  'mock' 'pytest' 'pytest-mock' 'coverage' 'pytest-cov' 'opentracing'
                                                                                                               'hypothesis<6.45.1' 'mysql-connector-python==8.0.5'
 #557   16025dc  mysql    Interpreter(_hint='3.5')   DD_TESTING_RAISE=1 DD_REMOTE_CONFIGURATION_ENABLED=false  'mock' 'pytest' 'pytest-mock' 'coverage' 'pytest-cov' 'opentracing'
                                                                                                               'hypothesis<6.45.1' 'mysql-connector-python==8.0.23'
 #558   1cdb1c5  mysql    Interpreter(_hint='3.6')   DD_TESTING_RAISE=1 DD_REMOTE_CONFIGURATION_ENABLED=false  'mock' 'pytest' 'pytest-mock' 'coverage' 'pytest-cov' 'opentracing'
                                                                                                               'hypothesis<6.45.1' 'mysql-connector-python==8.0.5'
 #559   1230ff8  mysql    Interpreter(_hint='3.6')   DD_TESTING_RAISE=1 DD_REMOTE_CONFIGURATION_ENABLED=false  'mock' 'pytest' 'pytest-mock' 'coverage' 'pytest-cov' 'opentracing'
                                                                                                               'hypothesis<6.45.1' 'mysql-connector-python==8.0.29'
 #560   729b5a8  mysql    Interpreter(_hint='3.7')   DD_TESTING_RAISE=1 DD_REMOTE_CONFIGURATION_ENABLED=false  'mock' 'pytest' 'pytest-mock' 'coverage' 'pytest-cov' 'opentracing'
                                                                                                               'hypothesis<6.45.1' 'mysql-connector-python==8.0.5'
 #561   1133f63  mysql    Interpreter(_hint='3.7')   DD_TESTING_RAISE=1 DD_REMOTE_CONFIGURATION_ENABLED=false  'mock' 'pytest' 'pytest-mock' 'coverage' 'pytest-cov' 'opentracing'
                                                                                                               'hypothesis<6.45.1' 'mysql-connector-python'
 #562   129b0f2  mysql    Interpreter(_hint='3.8')   DD_TESTING_RAISE=1 DD_REMOTE_CONFIGURATION_ENABLED=false  'mock' 'pytest' 'pytest-mock' 'coverage' 'pytest-cov' 'opentracing'
                                                                                                               'hypothesis<6.45.1' 'mysql-connector-python==8.0.5'
 #563   12db871  mysql    Interpreter(_hint='3.8')   DD_TESTING_RAISE=1 DD_REMOTE_CONFIGURATION_ENABLED=false  'mock' 'pytest' 'pytest-mock' 'coverage' 'pytest-cov' 'opentracing'
                                                                                                               'hypothesis<6.45.1' 'mysql-connector-python'
 #564   270f95a  mysql    Interpreter(_hint='3.9')   DD_TESTING_RAISE=1 DD_REMOTE_CONFIGURATION_ENABLED=false  'mock' 'pytest' 'pytest-mock' 'coverage' 'pytest-cov' 'opentracing'
                                                                                                               'hypothesis<6.45.1' 'mysql-connector-python==8.0.5'
 #565   9182ae0  mysql    Interpreter(_hint='3.9')   DD_TESTING_RAISE=1 DD_REMOTE_CONFIGURATION_ENABLED=false  'mock' 'pytest' 'pytest-mock' 'coverage' 'pytest-cov' 'opentracing'
                                                                                                               'hypothesis<6.45.1' 'mysql-connector-python'
 #566   137147e  mysql    Interpreter(_hint='3.10')  DD_TESTING_RAISE=1 DD_REMOTE_CONFIGURATION_ENABLED=false  'mock' 'pytest' 'pytest-mock' 'coverage' 'pytest-cov' 'opentracing'
                                                                                                               'hypothesis<6.45.1' 'mysql-connector-python~=8.0.28'
 #567   f26af3b  mysql    Interpreter(_hint='3.10')  DD_TESTING_RAISE=1 DD_REMOTE_CONFIGURATION_ENABLED=false  'mock' 'pytest' 'pytest-mock' 'coverage' 'pytest-cov' 'opentracing'
                                                                                                               'hypothesis<6.45.1' 'mysql-connector-python'
 #568   2eb00ea  mysql    Interpreter(_hint='3.11')  DD_TESTING_RAISE=1 DD_REMOTE_CONFIGURATION_ENABLED=false  'mock' 'pytest' 'pytest-mock' 'coverage' 'pytest-cov' 'opentracing'
                                                                                                               'hypothesis<6.45.1' 'mysql-connector-python~=8.0.31'
 #569   10d623a  mysql    Interpreter(_hint='3.11')  DD_TESTING_RAISE=1 DD_REMOTE_CONFIGURATION_ENABLED=false  'mock' 'pytest' 'pytest-mock' 'coverage' 'pytest-cov' 'opentracing'
                                                                                                               'hypothesis<6.45.1' 'mysql-connector-python'
 #1450  9be82d5  mysqldb  Interpreter(_hint='2.7')   DD_TESTING_RAISE=1 DD_REMOTE_CONFIGURATION_ENABLED=false  'mock' 'pytest' 'pytest-mock' 'coverage' 'pytest-cov' 'opentracing'
                                                                                                               'hypothesis<6.45.1' 'mysqlclient~=1.4.6'
 #1451  17a3e91  mysqldb  Interpreter(_hint='3.5')   DD_TESTING_RAISE=1 DD_REMOTE_CONFIGURATION_ENABLED=false  'mock' 'pytest' 'pytest-mock' 'coverage' 'pytest-cov' 'opentracing'
                                                                                                               'hypothesis<6.45.1' 'mysqlclient~=1.4.6'
 #1452  1c338bf  mysqldb  Interpreter(_hint='3.6')   DD_TESTING_RAISE=1 DD_REMOTE_CONFIGURATION_ENABLED=false  'mock' 'pytest' 'pytest-mock' 'coverage' 'pytest-cov' 'opentracing'
                                                                                                               'hypothesis<6.45.1' 'mysqlclient~=2.0'
 #1453  162a527  mysqldb  Interpreter(_hint='3.6')   DD_TESTING_RAISE=1 DD_REMOTE_CONFIGURATION_ENABLED=false  'mock' 'pytest' 'pytest-mock' 'coverage' 'pytest-cov' 'opentracing'
                                                                                                               'hypothesis<6.45.1' 'mysqlclient~=2.1'
 #1454  19ef42f  mysqldb  Interpreter(_hint='3.6')   DD_TESTING_RAISE=1 DD_REMOTE_CONFIGURATION_ENABLED=false  'mock' 'pytest' 'pytest-mock' 'coverage' 'pytest-cov' 'opentracing'
                                                                                                               'hypothesis<6.45.1' 'mysqlclient'
 #1455  145f708  mysqldb  Interpreter(_hint='3.7')   DD_TESTING_RAISE=1 DD_REMOTE_CONFIGURATION_ENABLED=false  'mock' 'pytest' 'pytest-mock' 'coverage' 'pytest-cov' 'opentracing'
                                                                                                               'hypothesis<6.45.1' 'mysqlclient~=2.0'
 #1456  73a2d0b  mysqldb  Interpreter(_hint='3.7')   DD_TESTING_RAISE=1 DD_REMOTE_CONFIGURATION_ENABLED=false  'mock' 'pytest' 'pytest-mock' 'coverage' 'pytest-cov' 'opentracing'
                                                                                                               'hypothesis<6.45.1' 'mysqlclient~=2.1'
 #1457  11b2766  mysqldb  Interpreter(_hint='3.7')   DD_TESTING_RAISE=1 DD_REMOTE_CONFIGURATION_ENABLED=false  'mock' 'pytest' 'pytest-mock' 'coverage' 'pytest-cov' 'opentracing'
                                                                                                               'hypothesis<6.45.1' 'mysqlclient'
 #1458  1fcb3db  mysqldb  Interpreter(_hint='3.8')   DD_TESTING_RAISE=1 DD_REMOTE_CONFIGURATION_ENABLED=false  'mock' 'pytest' 'pytest-mock' 'coverage' 'pytest-cov' 'opentracing'
                                                                                                               'hypothesis<6.45.1' 'mysqlclient~=2.0'
 #1459  1c5e6ed  mysqldb  Interpreter(_hint='3.8')   DD_TESTING_RAISE=1 DD_REMOTE_CONFIGURATION_ENABLED=false  'mock' 'pytest' 'pytest-mock' 'coverage' 'pytest-cov' 'opentracing'
                                                                                                               'hypothesis<6.45.1' 'mysqlclient~=2.1'
 #1460  137f08a  mysqldb  Interpreter(_hint='3.8')   DD_TESTING_RAISE=1 DD_REMOTE_CONFIGURATION_ENABLED=false  'mock' 'pytest' 'pytest-mock' 'coverage' 'pytest-cov' 'opentracing'
                                                                                                               'hypothesis<6.45.1' 'mysqlclient'
 #1461  149f779  mysqldb  Interpreter(_hint='3.9')   DD_TESTING_RAISE=1 DD_REMOTE_CONFIGURATION_ENABLED=false  'mock' 'pytest' 'pytest-mock' 'coverage' 'pytest-cov' 'opentracing'
                                                                                                               'hypothesis<6.45.1' 'mysqlclient~=2.0'
 #1462  14a543a  mysqldb  Interpreter(_hint='3.9')   DD_TESTING_RAISE=1 DD_REMOTE_CONFIGURATION_ENABLED=false  'mock' 'pytest' 'pytest-mock' 'coverage' 'pytest-cov' 'opentracing'
                                                                                                               'hypothesis<6.45.1' 'mysqlclient~=2.1'
 #1463  1eea232  mysqldb  Interpreter(_hint='3.9')   DD_TESTING_RAISE=1 DD_REMOTE_CONFIGURATION_ENABLED=false  'mock' 'pytest' 'pytest-mock' 'coverage' 'pytest-cov' 'opentracing'
                                                                                                               'hypothesis<6.45.1' 'mysqlclient'
 #1464  14a543a  mysqldb  Interpreter(_hint='3.9')   DD_TESTING_RAISE=1 DD_REMOTE_CONFIGURATION_ENABLED=false  'mock' 'pytest' 'pytest-mock' 'coverage' 'pytest-cov' 'opentracing'
                                                                                                               'hypothesis<6.45.1' 'mysqlclient~=2.1'
 #1465  1eea232  mysqldb  Interpreter(_hint='3.9')   DD_TESTING_RAISE=1 DD_REMOTE_CONFIGURATION_ENABLED=false  'mock' 'pytest' 'pytest-mock' 'coverage' 'pytest-cov' 'opentracing'
                                                                                                               'hypothesis<6.45.1' 'mysqlclient'
 #1466  10bc6fe  mysqldb  Interpreter(_hint='3.10')  DD_TESTING_RAISE=1 DD_REMOTE_CONFIGURATION_ENABLED=false  'mock' 'pytest' 'pytest-mock' 'coverage' 'pytest-cov' 'opentracing'
                                                                                                               'hypothesis<6.45.1' 'mysqlclient~=2.1'
 #1467  bf00ea5  mysqldb  Interpreter(_hint='3.10')  DD_TESTING_RAISE=1 DD_REMOTE_CONFIGURATION_ENABLED=false  'mock' 'pytest' 'pytest-mock' 'coverage' 'pytest-cov' 'opentracing'
                                                                                                               'hypothesis<6.45.1' 'mysqlclient'
 #1468  186525e  mysqldb  Interpreter(_hint='3.11')  DD_TESTING_RAISE=1 DD_REMOTE_CONFIGURATION_ENABLED=false  'mock' 'pytest' 'pytest-mock' 'coverage' 'pytest-cov' 'opentracing'
                                                                                                               'hypothesis<6.45.1' 'mysqlclient~=2.1'
 #1469  8e13da5  mysqldb  Interpreter(_hint='3.11')  DD_TESTING_RAISE=1 DD_REMOTE_CONFIGURATION_ENABLED=false  'mock' 'pytest' 'pytest-mock' 'coverage' 'pytest-cov' 'opentracing'
                                                                                                               'hypothesis<6.45.1' 'mysqlclient'
```

</details>

<details>
<summary>After</summary>

```
❯ riot list "mysql$"
 No.   Hash     Name   Interpreter                Environment                                               Packages
 #554  1a1c1fa  mysql  Interpreter(_hint='2.7')   DD_TESTING_RAISE=1 DD_REMOTE_CONFIGURATION_ENABLED=false  'mock' 'pytest' 'pytest-mock' 'coverage' 'pytest-cov' 'opentracing'
                                                                                                            'hypothesis<6.45.1' 'mysql-connector-python==8.0.5'
 #555  8ba1245  mysql  Interpreter(_hint='2.7')   DD_TESTING_RAISE=1 DD_REMOTE_CONFIGURATION_ENABLED=false  'mock' 'pytest' 'pytest-mock' 'coverage' 'pytest-cov' 'opentracing'
                                                                                                            'hypothesis<6.45.1' 'mysql-connector-python==8.0.23'
 #556  1e72d9c  mysql  Interpreter(_hint='3.5')   DD_TESTING_RAISE=1 DD_REMOTE_CONFIGURATION_ENABLED=false  'mock' 'pytest' 'pytest-mock' 'coverage' 'pytest-cov' 'opentracing'
                                                                                                            'hypothesis<6.45.1' 'mysql-connector-python==8.0.5'
 #557  16025dc  mysql  Interpreter(_hint='3.5')   DD_TESTING_RAISE=1 DD_REMOTE_CONFIGURATION_ENABLED=false  'mock' 'pytest' 'pytest-mock' 'coverage' 'pytest-cov' 'opentracing'
                                                                                                            'hypothesis<6.45.1' 'mysql-connector-python==8.0.23'
 #558  1cdb1c5  mysql  Interpreter(_hint='3.6')   DD_TESTING_RAISE=1 DD_REMOTE_CONFIGURATION_ENABLED=false  'mock' 'pytest' 'pytest-mock' 'coverage' 'pytest-cov' 'opentracing'
                                                                                                            'hypothesis<6.45.1' 'mysql-connector-python==8.0.5'
 #559  1230ff8  mysql  Interpreter(_hint='3.6')   DD_TESTING_RAISE=1 DD_REMOTE_CONFIGURATION_ENABLED=false  'mock' 'pytest' 'pytest-mock' 'coverage' 'pytest-cov' 'opentracing'
                                                                                                            'hypothesis<6.45.1' 'mysql-connector-python==8.0.29'
 #560  729b5a8  mysql  Interpreter(_hint='3.7')   DD_TESTING_RAISE=1 DD_REMOTE_CONFIGURATION_ENABLED=false  'mock' 'pytest' 'pytest-mock' 'coverage' 'pytest-cov' 'opentracing'
                                                                                                            'hypothesis<6.45.1' 'mysql-connector-python==8.0.5'
 #561  1133f63  mysql  Interpreter(_hint='3.7')   DD_TESTING_RAISE=1 DD_REMOTE_CONFIGURATION_ENABLED=false  'mock' 'pytest' 'pytest-mock' 'coverage' 'pytest-cov' 'opentracing'
                                                                                                            'hypothesis<6.45.1' 'mysql-connector-python'
 #562  129b0f2  mysql  Interpreter(_hint='3.8')   DD_TESTING_RAISE=1 DD_REMOTE_CONFIGURATION_ENABLED=false  'mock' 'pytest' 'pytest-mock' 'coverage' 'pytest-cov' 'opentracing'
                                                                                                            'hypothesis<6.45.1' 'mysql-connector-python==8.0.5'
 #563  12db871  mysql  Interpreter(_hint='3.8')   DD_TESTING_RAISE=1 DD_REMOTE_CONFIGURATION_ENABLED=false  'mock' 'pytest' 'pytest-mock' 'coverage' 'pytest-cov' 'opentracing'
                                                                                                            'hypothesis<6.45.1' 'mysql-connector-python'
 #564  270f95a  mysql  Interpreter(_hint='3.9')   DD_TESTING_RAISE=1 DD_REMOTE_CONFIGURATION_ENABLED=false  'mock' 'pytest' 'pytest-mock' 'coverage' 'pytest-cov' 'opentracing'
                                                                                                            'hypothesis<6.45.1' 'mysql-connector-python==8.0.5'
 #565  9182ae0  mysql  Interpreter(_hint='3.9')   DD_TESTING_RAISE=1 DD_REMOTE_CONFIGURATION_ENABLED=false  'mock' 'pytest' 'pytest-mock' 'coverage' 'pytest-cov' 'opentracing'
                                                                                                            'hypothesis<6.45.1' 'mysql-connector-python'
 #566  137147e  mysql  Interpreter(_hint='3.10')  DD_TESTING_RAISE=1 DD_REMOTE_CONFIGURATION_ENABLED=false  'mock' 'pytest' 'pytest-mock' 'coverage' 'pytest-cov' 'opentracing'
                                                                                                            'hypothesis<6.45.1' 'mysql-connector-python~=8.0.28'
 #567  f26af3b  mysql  Interpreter(_hint='3.10')  DD_TESTING_RAISE=1 DD_REMOTE_CONFIGURATION_ENABLED=false  'mock' 'pytest' 'pytest-mock' 'coverage' 'pytest-cov' 'opentracing'
                                                                                                            'hypothesis<6.45.1' 'mysql-connector-python'
 #568  2eb00ea  mysql  Interpreter(_hint='3.11')  DD_TESTING_RAISE=1 DD_REMOTE_CONFIGURATION_ENABLED=false  'mock' 'pytest' 'pytest-mock' 'coverage' 'pytest-cov' 'opentracing'
                                                                                                            'hypothesis<6.45.1' 'mysql-connector-python~=8.0.31'
 #569  10d623a  mysql  Interpreter(_hint='3.11')  DD_TESTING_RAISE=1 DD_REMOTE_CONFIGURATION_ENABLED=false  'mock' 'pytest' 'pytest-mock' 'coverage' 'pytest-cov' 'opentracing'
                                                                                                            'hypothesis<6.45.1' 'mysql-connector-python'
```

</details>

### Improve wait job runtime

The `wait` job was not running with `-s` and was trying to install the
dev package this meant it was taking 3+ minutes to run the `wait` job.
We updated the job to ensure it does not install the dev package. Now it
runs in <30 seconds.

### Properly restore workspace from build_base_venvs

Through debugging we noticed that we were building the base
venv/installing dev package in scenarios when we should not have.

This is because we were storing the workspace/venvs from
`build_base_venvs` incorrectly causing us to reinstall the dev package
once per-job * per-node * per-python version.

The fix was to checkout the code first and then restore the files from
the workspace.

The only lead I have as to why/when this started happening is when we
added `.riot/requirements/` if the git checkout was overwriting the
exiting `.riot/` directory added from the workspace?

### Adjusted parallelism

Now that runtime of jobs is improved we can safe some credits by
reducing parallelism.

## Checklist

- [x] Change(s) are motivated and described in the PR description.
- [x] Testing strategy is described if automated tests are not included
in the PR.
- [x] Risk is outlined (performance impact, potential for breakage,
maintainability, etc).
- [x] Change is maintainable (easy to change, telemetry, documentation).
- [x] [Library release note
guidelines](https://ddtrace.readthedocs.io/en/stable/releasenotes.html)
are followed. If no release note is required, add label
`changelog/no-changelog`.
- [x] Documentation is included (in-code, generated user docs, [public
corp docs](https://github.com/DataDog/documentation/)).
- [x] Backport labels are set (if
[applicable](https://ddtrace.readthedocs.io/en/latest/contributing.html#backporting))

## Reviewer Checklist

- [ ] Title is accurate.
- [ ] No unnecessary changes are introduced.
- [ ] Description motivates each change.
- [ ] Avoids breaking
[API](https://ddtrace.readthedocs.io/en/stable/versioning.html#interfaces)
changes unless absolutely necessary.
- [ ] Testing strategy adequately addresses listed risk(s).
- [ ] Change is maintainable (easy to change, telemetry, documentation).
- [ ] Release note makes sense to a user of the library.
- [ ] Reviewer has explicitly acknowledged and discussed the performance
implications of this PR as reported in the benchmarks PR comment.
- [ ] Backport labels are set in a manner that is consistent with the
[release branch maintenance
policy](https://ddtrace.readthedocs.io/en/latest/contributing.html#backporting)
romainkomorndatadog pushed a commit that referenced this pull request Aug 8, 2023
This fix introduces a few changes to improve overall CircleCI job
runtime.

**Before:**
- Runtime: 28+ minutes
- Credits: 33k

**After:**
- Runtime: ~22 minutes (-20%)
- Credits: ~15k (-55%)

### Fix mysql test pattern

The `mysql` CircleCI job was using the pattern "mysql", which would also
match the `mysqldb` jobs.

This change updates the test pattern for all mysql jobs to include an
ending `$`.


<details>
<summary>Before</summary>

```
❯ riot list mysql
 No.    Hash     Name     Interpreter                Environment                                               Packages
 #554   1a1c1fa  mysql    Interpreter(_hint='2.7')   DD_TESTING_RAISE=1 DD_REMOTE_CONFIGURATION_ENABLED=false  'mock' 'pytest' 'pytest-mock' 'coverage' 'pytest-cov' 'opentracing'
                                                                                                               'hypothesis<6.45.1' 'mysql-connector-python==8.0.5'
 #555   8ba1245  mysql    Interpreter(_hint='2.7')   DD_TESTING_RAISE=1 DD_REMOTE_CONFIGURATION_ENABLED=false  'mock' 'pytest' 'pytest-mock' 'coverage' 'pytest-cov' 'opentracing'
                                                                                                               'hypothesis<6.45.1' 'mysql-connector-python==8.0.23'
 #556   1e72d9c  mysql    Interpreter(_hint='3.5')   DD_TESTING_RAISE=1 DD_REMOTE_CONFIGURATION_ENABLED=false  'mock' 'pytest' 'pytest-mock' 'coverage' 'pytest-cov' 'opentracing'
                                                                                                               'hypothesis<6.45.1' 'mysql-connector-python==8.0.5'
 #557   16025dc  mysql    Interpreter(_hint='3.5')   DD_TESTING_RAISE=1 DD_REMOTE_CONFIGURATION_ENABLED=false  'mock' 'pytest' 'pytest-mock' 'coverage' 'pytest-cov' 'opentracing'
                                                                                                               'hypothesis<6.45.1' 'mysql-connector-python==8.0.23'
 #558   1cdb1c5  mysql    Interpreter(_hint='3.6')   DD_TESTING_RAISE=1 DD_REMOTE_CONFIGURATION_ENABLED=false  'mock' 'pytest' 'pytest-mock' 'coverage' 'pytest-cov' 'opentracing'
                                                                                                               'hypothesis<6.45.1' 'mysql-connector-python==8.0.5'
 #559   1230ff8  mysql    Interpreter(_hint='3.6')   DD_TESTING_RAISE=1 DD_REMOTE_CONFIGURATION_ENABLED=false  'mock' 'pytest' 'pytest-mock' 'coverage' 'pytest-cov' 'opentracing'
                                                                                                               'hypothesis<6.45.1' 'mysql-connector-python==8.0.29'
 #560   729b5a8  mysql    Interpreter(_hint='3.7')   DD_TESTING_RAISE=1 DD_REMOTE_CONFIGURATION_ENABLED=false  'mock' 'pytest' 'pytest-mock' 'coverage' 'pytest-cov' 'opentracing'
                                                                                                               'hypothesis<6.45.1' 'mysql-connector-python==8.0.5'
 #561   1133f63  mysql    Interpreter(_hint='3.7')   DD_TESTING_RAISE=1 DD_REMOTE_CONFIGURATION_ENABLED=false  'mock' 'pytest' 'pytest-mock' 'coverage' 'pytest-cov' 'opentracing'
                                                                                                               'hypothesis<6.45.1' 'mysql-connector-python'
 #562   129b0f2  mysql    Interpreter(_hint='3.8')   DD_TESTING_RAISE=1 DD_REMOTE_CONFIGURATION_ENABLED=false  'mock' 'pytest' 'pytest-mock' 'coverage' 'pytest-cov' 'opentracing'
                                                                                                               'hypothesis<6.45.1' 'mysql-connector-python==8.0.5'
 #563   12db871  mysql    Interpreter(_hint='3.8')   DD_TESTING_RAISE=1 DD_REMOTE_CONFIGURATION_ENABLED=false  'mock' 'pytest' 'pytest-mock' 'coverage' 'pytest-cov' 'opentracing'
                                                                                                               'hypothesis<6.45.1' 'mysql-connector-python'
 #564   270f95a  mysql    Interpreter(_hint='3.9')   DD_TESTING_RAISE=1 DD_REMOTE_CONFIGURATION_ENABLED=false  'mock' 'pytest' 'pytest-mock' 'coverage' 'pytest-cov' 'opentracing'
                                                                                                               'hypothesis<6.45.1' 'mysql-connector-python==8.0.5'
 #565   9182ae0  mysql    Interpreter(_hint='3.9')   DD_TESTING_RAISE=1 DD_REMOTE_CONFIGURATION_ENABLED=false  'mock' 'pytest' 'pytest-mock' 'coverage' 'pytest-cov' 'opentracing'
                                                                                                               'hypothesis<6.45.1' 'mysql-connector-python'
 #566   137147e  mysql    Interpreter(_hint='3.10')  DD_TESTING_RAISE=1 DD_REMOTE_CONFIGURATION_ENABLED=false  'mock' 'pytest' 'pytest-mock' 'coverage' 'pytest-cov' 'opentracing'
                                                                                                               'hypothesis<6.45.1' 'mysql-connector-python~=8.0.28'
 #567   f26af3b  mysql    Interpreter(_hint='3.10')  DD_TESTING_RAISE=1 DD_REMOTE_CONFIGURATION_ENABLED=false  'mock' 'pytest' 'pytest-mock' 'coverage' 'pytest-cov' 'opentracing'
                                                                                                               'hypothesis<6.45.1' 'mysql-connector-python'
 #568   2eb00ea  mysql    Interpreter(_hint='3.11')  DD_TESTING_RAISE=1 DD_REMOTE_CONFIGURATION_ENABLED=false  'mock' 'pytest' 'pytest-mock' 'coverage' 'pytest-cov' 'opentracing'
                                                                                                               'hypothesis<6.45.1' 'mysql-connector-python~=8.0.31'
 #569   10d623a  mysql    Interpreter(_hint='3.11')  DD_TESTING_RAISE=1 DD_REMOTE_CONFIGURATION_ENABLED=false  'mock' 'pytest' 'pytest-mock' 'coverage' 'pytest-cov' 'opentracing'
                                                                                                               'hypothesis<6.45.1' 'mysql-connector-python'
 #1450  9be82d5  mysqldb  Interpreter(_hint='2.7')   DD_TESTING_RAISE=1 DD_REMOTE_CONFIGURATION_ENABLED=false  'mock' 'pytest' 'pytest-mock' 'coverage' 'pytest-cov' 'opentracing'
                                                                                                               'hypothesis<6.45.1' 'mysqlclient~=1.4.6'
 #1451  17a3e91  mysqldb  Interpreter(_hint='3.5')   DD_TESTING_RAISE=1 DD_REMOTE_CONFIGURATION_ENABLED=false  'mock' 'pytest' 'pytest-mock' 'coverage' 'pytest-cov' 'opentracing'
                                                                                                               'hypothesis<6.45.1' 'mysqlclient~=1.4.6'
 #1452  1c338bf  mysqldb  Interpreter(_hint='3.6')   DD_TESTING_RAISE=1 DD_REMOTE_CONFIGURATION_ENABLED=false  'mock' 'pytest' 'pytest-mock' 'coverage' 'pytest-cov' 'opentracing'
                                                                                                               'hypothesis<6.45.1' 'mysqlclient~=2.0'
 #1453  162a527  mysqldb  Interpreter(_hint='3.6')   DD_TESTING_RAISE=1 DD_REMOTE_CONFIGURATION_ENABLED=false  'mock' 'pytest' 'pytest-mock' 'coverage' 'pytest-cov' 'opentracing'
                                                                                                               'hypothesis<6.45.1' 'mysqlclient~=2.1'
 #1454  19ef42f  mysqldb  Interpreter(_hint='3.6')   DD_TESTING_RAISE=1 DD_REMOTE_CONFIGURATION_ENABLED=false  'mock' 'pytest' 'pytest-mock' 'coverage' 'pytest-cov' 'opentracing'
                                                                                                               'hypothesis<6.45.1' 'mysqlclient'
 #1455  145f708  mysqldb  Interpreter(_hint='3.7')   DD_TESTING_RAISE=1 DD_REMOTE_CONFIGURATION_ENABLED=false  'mock' 'pytest' 'pytest-mock' 'coverage' 'pytest-cov' 'opentracing'
                                                                                                               'hypothesis<6.45.1' 'mysqlclient~=2.0'
 #1456  73a2d0b  mysqldb  Interpreter(_hint='3.7')   DD_TESTING_RAISE=1 DD_REMOTE_CONFIGURATION_ENABLED=false  'mock' 'pytest' 'pytest-mock' 'coverage' 'pytest-cov' 'opentracing'
                                                                                                               'hypothesis<6.45.1' 'mysqlclient~=2.1'
 #1457  11b2766  mysqldb  Interpreter(_hint='3.7')   DD_TESTING_RAISE=1 DD_REMOTE_CONFIGURATION_ENABLED=false  'mock' 'pytest' 'pytest-mock' 'coverage' 'pytest-cov' 'opentracing'
                                                                                                               'hypothesis<6.45.1' 'mysqlclient'
 #1458  1fcb3db  mysqldb  Interpreter(_hint='3.8')   DD_TESTING_RAISE=1 DD_REMOTE_CONFIGURATION_ENABLED=false  'mock' 'pytest' 'pytest-mock' 'coverage' 'pytest-cov' 'opentracing'
                                                                                                               'hypothesis<6.45.1' 'mysqlclient~=2.0'
 #1459  1c5e6ed  mysqldb  Interpreter(_hint='3.8')   DD_TESTING_RAISE=1 DD_REMOTE_CONFIGURATION_ENABLED=false  'mock' 'pytest' 'pytest-mock' 'coverage' 'pytest-cov' 'opentracing'
                                                                                                               'hypothesis<6.45.1' 'mysqlclient~=2.1'
 #1460  137f08a  mysqldb  Interpreter(_hint='3.8')   DD_TESTING_RAISE=1 DD_REMOTE_CONFIGURATION_ENABLED=false  'mock' 'pytest' 'pytest-mock' 'coverage' 'pytest-cov' 'opentracing'
                                                                                                               'hypothesis<6.45.1' 'mysqlclient'
 #1461  149f779  mysqldb  Interpreter(_hint='3.9')   DD_TESTING_RAISE=1 DD_REMOTE_CONFIGURATION_ENABLED=false  'mock' 'pytest' 'pytest-mock' 'coverage' 'pytest-cov' 'opentracing'
                                                                                                               'hypothesis<6.45.1' 'mysqlclient~=2.0'
 #1462  14a543a  mysqldb  Interpreter(_hint='3.9')   DD_TESTING_RAISE=1 DD_REMOTE_CONFIGURATION_ENABLED=false  'mock' 'pytest' 'pytest-mock' 'coverage' 'pytest-cov' 'opentracing'
                                                                                                               'hypothesis<6.45.1' 'mysqlclient~=2.1'
 #1463  1eea232  mysqldb  Interpreter(_hint='3.9')   DD_TESTING_RAISE=1 DD_REMOTE_CONFIGURATION_ENABLED=false  'mock' 'pytest' 'pytest-mock' 'coverage' 'pytest-cov' 'opentracing'
                                                                                                               'hypothesis<6.45.1' 'mysqlclient'
 #1464  14a543a  mysqldb  Interpreter(_hint='3.9')   DD_TESTING_RAISE=1 DD_REMOTE_CONFIGURATION_ENABLED=false  'mock' 'pytest' 'pytest-mock' 'coverage' 'pytest-cov' 'opentracing'
                                                                                                               'hypothesis<6.45.1' 'mysqlclient~=2.1'
 #1465  1eea232  mysqldb  Interpreter(_hint='3.9')   DD_TESTING_RAISE=1 DD_REMOTE_CONFIGURATION_ENABLED=false  'mock' 'pytest' 'pytest-mock' 'coverage' 'pytest-cov' 'opentracing'
                                                                                                               'hypothesis<6.45.1' 'mysqlclient'
 #1466  10bc6fe  mysqldb  Interpreter(_hint='3.10')  DD_TESTING_RAISE=1 DD_REMOTE_CONFIGURATION_ENABLED=false  'mock' 'pytest' 'pytest-mock' 'coverage' 'pytest-cov' 'opentracing'
                                                                                                               'hypothesis<6.45.1' 'mysqlclient~=2.1'
 #1467  bf00ea5  mysqldb  Interpreter(_hint='3.10')  DD_TESTING_RAISE=1 DD_REMOTE_CONFIGURATION_ENABLED=false  'mock' 'pytest' 'pytest-mock' 'coverage' 'pytest-cov' 'opentracing'
                                                                                                               'hypothesis<6.45.1' 'mysqlclient'
 #1468  186525e  mysqldb  Interpreter(_hint='3.11')  DD_TESTING_RAISE=1 DD_REMOTE_CONFIGURATION_ENABLED=false  'mock' 'pytest' 'pytest-mock' 'coverage' 'pytest-cov' 'opentracing'
                                                                                                               'hypothesis<6.45.1' 'mysqlclient~=2.1'
 #1469  8e13da5  mysqldb  Interpreter(_hint='3.11')  DD_TESTING_RAISE=1 DD_REMOTE_CONFIGURATION_ENABLED=false  'mock' 'pytest' 'pytest-mock' 'coverage' 'pytest-cov' 'opentracing'
                                                                                                               'hypothesis<6.45.1' 'mysqlclient'
```

</details>

<details>
<summary>After</summary>

```
❯ riot list "mysql$"
 No.   Hash     Name   Interpreter                Environment                                               Packages
 #554  1a1c1fa  mysql  Interpreter(_hint='2.7')   DD_TESTING_RAISE=1 DD_REMOTE_CONFIGURATION_ENABLED=false  'mock' 'pytest' 'pytest-mock' 'coverage' 'pytest-cov' 'opentracing'
                                                                                                            'hypothesis<6.45.1' 'mysql-connector-python==8.0.5'
 #555  8ba1245  mysql  Interpreter(_hint='2.7')   DD_TESTING_RAISE=1 DD_REMOTE_CONFIGURATION_ENABLED=false  'mock' 'pytest' 'pytest-mock' 'coverage' 'pytest-cov' 'opentracing'
                                                                                                            'hypothesis<6.45.1' 'mysql-connector-python==8.0.23'
 #556  1e72d9c  mysql  Interpreter(_hint='3.5')   DD_TESTING_RAISE=1 DD_REMOTE_CONFIGURATION_ENABLED=false  'mock' 'pytest' 'pytest-mock' 'coverage' 'pytest-cov' 'opentracing'
                                                                                                            'hypothesis<6.45.1' 'mysql-connector-python==8.0.5'
 #557  16025dc  mysql  Interpreter(_hint='3.5')   DD_TESTING_RAISE=1 DD_REMOTE_CONFIGURATION_ENABLED=false  'mock' 'pytest' 'pytest-mock' 'coverage' 'pytest-cov' 'opentracing'
                                                                                                            'hypothesis<6.45.1' 'mysql-connector-python==8.0.23'
 #558  1cdb1c5  mysql  Interpreter(_hint='3.6')   DD_TESTING_RAISE=1 DD_REMOTE_CONFIGURATION_ENABLED=false  'mock' 'pytest' 'pytest-mock' 'coverage' 'pytest-cov' 'opentracing'
                                                                                                            'hypothesis<6.45.1' 'mysql-connector-python==8.0.5'
 #559  1230ff8  mysql  Interpreter(_hint='3.6')   DD_TESTING_RAISE=1 DD_REMOTE_CONFIGURATION_ENABLED=false  'mock' 'pytest' 'pytest-mock' 'coverage' 'pytest-cov' 'opentracing'
                                                                                                            'hypothesis<6.45.1' 'mysql-connector-python==8.0.29'
 #560  729b5a8  mysql  Interpreter(_hint='3.7')   DD_TESTING_RAISE=1 DD_REMOTE_CONFIGURATION_ENABLED=false  'mock' 'pytest' 'pytest-mock' 'coverage' 'pytest-cov' 'opentracing'
                                                                                                            'hypothesis<6.45.1' 'mysql-connector-python==8.0.5'
 #561  1133f63  mysql  Interpreter(_hint='3.7')   DD_TESTING_RAISE=1 DD_REMOTE_CONFIGURATION_ENABLED=false  'mock' 'pytest' 'pytest-mock' 'coverage' 'pytest-cov' 'opentracing'
                                                                                                            'hypothesis<6.45.1' 'mysql-connector-python'
 #562  129b0f2  mysql  Interpreter(_hint='3.8')   DD_TESTING_RAISE=1 DD_REMOTE_CONFIGURATION_ENABLED=false  'mock' 'pytest' 'pytest-mock' 'coverage' 'pytest-cov' 'opentracing'
                                                                                                            'hypothesis<6.45.1' 'mysql-connector-python==8.0.5'
 #563  12db871  mysql  Interpreter(_hint='3.8')   DD_TESTING_RAISE=1 DD_REMOTE_CONFIGURATION_ENABLED=false  'mock' 'pytest' 'pytest-mock' 'coverage' 'pytest-cov' 'opentracing'
                                                                                                            'hypothesis<6.45.1' 'mysql-connector-python'
 #564  270f95a  mysql  Interpreter(_hint='3.9')   DD_TESTING_RAISE=1 DD_REMOTE_CONFIGURATION_ENABLED=false  'mock' 'pytest' 'pytest-mock' 'coverage' 'pytest-cov' 'opentracing'
                                                                                                            'hypothesis<6.45.1' 'mysql-connector-python==8.0.5'
 #565  9182ae0  mysql  Interpreter(_hint='3.9')   DD_TESTING_RAISE=1 DD_REMOTE_CONFIGURATION_ENABLED=false  'mock' 'pytest' 'pytest-mock' 'coverage' 'pytest-cov' 'opentracing'
                                                                                                            'hypothesis<6.45.1' 'mysql-connector-python'
 #566  137147e  mysql  Interpreter(_hint='3.10')  DD_TESTING_RAISE=1 DD_REMOTE_CONFIGURATION_ENABLED=false  'mock' 'pytest' 'pytest-mock' 'coverage' 'pytest-cov' 'opentracing'
                                                                                                            'hypothesis<6.45.1' 'mysql-connector-python~=8.0.28'
 #567  f26af3b  mysql  Interpreter(_hint='3.10')  DD_TESTING_RAISE=1 DD_REMOTE_CONFIGURATION_ENABLED=false  'mock' 'pytest' 'pytest-mock' 'coverage' 'pytest-cov' 'opentracing'
                                                                                                            'hypothesis<6.45.1' 'mysql-connector-python'
 #568  2eb00ea  mysql  Interpreter(_hint='3.11')  DD_TESTING_RAISE=1 DD_REMOTE_CONFIGURATION_ENABLED=false  'mock' 'pytest' 'pytest-mock' 'coverage' 'pytest-cov' 'opentracing'
                                                                                                            'hypothesis<6.45.1' 'mysql-connector-python~=8.0.31'
 #569  10d623a  mysql  Interpreter(_hint='3.11')  DD_TESTING_RAISE=1 DD_REMOTE_CONFIGURATION_ENABLED=false  'mock' 'pytest' 'pytest-mock' 'coverage' 'pytest-cov' 'opentracing'
                                                                                                            'hypothesis<6.45.1' 'mysql-connector-python'
```

</details>

### Improve wait job runtime

The `wait` job was not running with `-s` and was trying to install the
dev package this meant it was taking 3+ minutes to run the `wait` job.
We updated the job to ensure it does not install the dev package. Now it
runs in <30 seconds.

### Properly restore workspace from build_base_venvs

Through debugging we noticed that we were building the base
venv/installing dev package in scenarios when we should not have.

This is because we were storing the workspace/venvs from
`build_base_venvs` incorrectly causing us to reinstall the dev package
once per-job * per-node * per-python version.

The fix was to checkout the code first and then restore the files from
the workspace.

The only lead I have as to why/when this started happening is when we
added `.riot/requirements/` if the git checkout was overwriting the
exiting `.riot/` directory added from the workspace?

### Adjusted parallelism

Now that runtime of jobs is improved we can safe some credits by
reducing parallelism.

## Checklist

- [x] Change(s) are motivated and described in the PR description.
- [x] Testing strategy is described if automated tests are not included
in the PR.
- [x] Risk is outlined (performance impact, potential for breakage,
maintainability, etc).
- [x] Change is maintainable (easy to change, telemetry, documentation).
- [x] [Library release note
guidelines](https://ddtrace.readthedocs.io/en/stable/releasenotes.html)
are followed. If no release note is required, add label
`changelog/no-changelog`.
- [x] Documentation is included (in-code, generated user docs, [public
corp docs](https://github.com/DataDog/documentation/)).
- [x] Backport labels are set (if
[applicable](https://ddtrace.readthedocs.io/en/latest/contributing.html#backporting))

## Reviewer Checklist

- [ ] Title is accurate.
- [ ] No unnecessary changes are introduced.
- [ ] Description motivates each change.
- [ ] Avoids breaking
[API](https://ddtrace.readthedocs.io/en/stable/versioning.html#interfaces)
changes unless absolutely necessary.
- [ ] Testing strategy adequately addresses listed risk(s).
- [ ] Change is maintainable (easy to change, telemetry, documentation).
- [ ] Release note makes sense to a user of the library.
- [ ] Reviewer has explicitly acknowledged and discussed the performance
implications of this PR as reported in the benchmarks PR comment.
- [ ] Backport labels are set in a manner that is consistent with the
[release branch maintenance
policy](https://ddtrace.readthedocs.io/en/latest/contributing.html#backporting)
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.

None yet

2 participants