using pip dependencies outside of docker

Sometimes you need to obtain dependencies outside of building your application container:

  • to ensure exactly the same whl is used during testing as is used in the application
  • to authenticate with private package repositories

Here’s a technique for doing this using GitHub actions. Firstly, the dockerfile snippet:

COPY ./requirements.txt .
COPY ./deps /var/deps
# See https://pip.pypa.io/en/stable/user_guide/#installing-from-local-packages
RUN python -m pip install --no-index --find-links=/var/deps -r requirements.txt

It is very important that you use the same version of python in your GitHub actions that your docker container uses because different whl variants will be downloaded for say, python 3.9 compared to python 3.10.

 - name: Setup python matching dockerfile
   uses: actions/setup-python@v2
   with:
     python-version: 3.10 # Must match the dockerfile python version

 - name: Download dependencies
   env:
     PIP_INDEX_URL: ${{ secrets.PACKAGE_REPO_URL }}
   run: |
     mkdir deps
     pip download -r requirements.txt --destination-directory ./deps

This does have the downside that the whl packages exist as a redundant layer in the container. If anyone knows a way to remove this, please do add a comment.

Solved: Cannot sign into OneNote 2016 on Windows 10 with Office 365 “Work account”

Rebuilding my laptop and reinstalling Office 365, I wanted to log into OneNote and found I was stuck in a loop where:

  • it either wouldn’t add the work account but didn’t show an error
  • partially sync’d the notebook (showed section headings but then reported “Couldn’t open this section”)
  • OneNote reported sync error code 0x80073D02 (shown by clicking warning triangle in top right of OneNote)

Eventually I resolved this by adding the work account to Windows via start -> Manage your account (system settings) -> Access work or school (shown on left). This appears to add a link to my Office 365 Azure AD but more importantly I was then able to add the account to OneNote too.

aspnetcore MemoryCache “magic” dependencies and danger

TL;DR A method whose result must be cached for 12 hours, makes a call to a method that caches for 5 minutes. This transparently causes the caller to also get a 5 minute expiry instead of the 12 hours specified!

 
var result = await memoryCache.GetOrCreateAsync(
  "mykey",
  async entry =>
  {
    entry.AbsoluteExpiration = DateTime.Now.AddHours(12);
                   
    var other = await OtherMethodThatCachesAt5Minutes();

    return "I should be cached for 12 hours! But I'm cached for 5 minutes";
});

https://github.com/aspnet/Caching/commit/f15fb804cdc2e14f9a64896817f3c6c343110820#diff-9968fc5543acfd05fa60089bd344679bR102

Track fixes/comments for the issue at:
https://github.com/aspnet/Extensions/issues/1130

Why would they deliberately do this?

There is a logic to this approach, if the child method has data that must be refreshed every 5 minutes then the parent must also ensure it is using this up-to-date information.

When would this side-effect be unwanted?

Consider the scenario:

  • ProductService calls ConfigurationService (which happens to cache its config values for 5 minutes)
  • ProductService does some long-running calculations using this configuration, including calling systems that have quota limits. The ProductService sets the AbsoluteExpiry to (now + 12 hours).

Unknown to the ProductService, its result will not be cached for 12 hours but 5 minutes, leading to more calls of the system that has quota limits.

Why is it bad?

When one cache entry is used to create another, the child copies the parent entry’s expiration tokens and time-based expiration settings. The child isn’t expired by manual removal or updating of the parent entry.

  • Testing cache expiry is notoriously difficult.
    • The MemoryCache has no methods to extract the CacheEntries to examine the actual expiry applied without resorting to reflection
    • Typically method B will be in a dependent class that is mocked during unit testing – only the combination of calls causes the issue
    • Testers are unlikely to spot the difference in timeouts between A and B or that A is being called more frequently than it should be – perhaps until the system hits production where any quotas are more likely to be hit!
  • Using side-effects is risky and doesn’t always lead to the desired behaviour.

Is there some repro for this?

Unfortunately it’s a bit wordy due to the lack of public methods on MemoryCache:

        // GET api/values
        [HttpGet]
        public async Task Get()
        {
            var result = await _memoryCache.GetOrCreateAsync("mykey",
                async entry =>
                {
                    entry.AbsoluteExpiration = DateTime.Now.AddHours(12);
                    
                    var other = await OtherMethod();

                    // And call a system that has a quota meaning I shouldn't be calling too often 
                    // ...

                    return new string[] {"value1", "value2"};
                });

            var memoryCache = typeof(Microsoft.Extensions.Caching.Memory.MemoryCache)
                .GetField("_entries", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)
                .GetValue(_memoryCache);
            var cacheDictionaryType = memoryCache.GetType();
            var cacheEntry = cacheDictionaryType.GetProperty("Item").GetValue(memoryCache, new[] { "mykey" });
            var expiration = (DateTimeOffset)cacheEntry.GetType().GetProperty("AbsoluteExpiration").GetValue(cacheEntry);
            if (expiration.Offset.TotalMinutes < 60)
            {
                throw new Exception("What? I set the absolute expiration to 12 hours");
            }

            return result;
        }

        private async Task OtherMethod()
        {
            return await _memoryCache.GetOrCreateAsync("myotherkey",
                async otherEntry =>
                {
                    otherEntry.AbsoluteExpiration = DateTime.UtcNow.Add(TimeSpan.FromMinutes(5));                    

                    return "my other data";
                });
        }

How do I ensure my AbsoluteExpiry is applied without knowing what child classes are doing? A change in their timeouts could break my code!

An excellent question! Creating a new MemoryCache does not solve the issue because no-one told these coders that “static” is a bad idea:

https://github.com/aspnet/Extensions/blob/9bc79b2f25a3724376d7af19617c33749a30ea3a/src/Caching/Memory/src/CacheEntryHelper.cs#L11

This means you can’t even create a completely separate MemoryCache as it shares a static pool of scopes. They’ve also not provided a way for you to create your own scope to work around this – all the scopes are internal.

Since I want my particular value to be long lived, I’m going for the Lazy option.

Kubernetes, Azure Dev Spaces and Visual Studio

Some powerful tech in the title, this isn’t so much a blog article but a correction to some out of date Internet information that might help someone looking for a brief moment till the links change again.

https://hanselman.com/blog/AnnouncingVisualStudioAndKubernetesVisualStudioConnectedEnvironment.aspx

Great article and nice short video that captures just enough imagination! However, the link to http://aka.ms/signup-vsce will now give you a 404.

Instead, head to:

az aks use-dev-spaces -g MyResourceGroup -n MyAKS

 

Workaround: ReactScriptLoadException: Error while loading “~/build/server.bundle.js”: ReferenceError setTimeout is not defined

For a pet project I have Visual Studio Online using npm to install webpack and run a gulp task to package my ReactJS app that uses ReactJS.net serverside rendering.

However when it deployed to the server, an error was shown that was not encountered locally:

ReactScriptLoadException: Error while loading “~/build/server.bundle.js”: ReferenceError setTimeout is not defined

I tracked the difference between my local execution (which works) and my server deploy to a point release difference in webpack 1.13.0 vs. 1.13.1. My package.json file had “webpack”: “^1.13.0” so VSO was installing the latest which was 1.13.1 but locally I still had 1.13.0 as I am not currently running npm automatically.

As a temporary workaround for this issue (and preferable way forward) I’ve removed the carat and opted to use webpack 1.13.0 explicitly (something I should have done in the first place) but I haven’t looked into why the behavioural change is occurring yet.

Intermittent “The request was aborted: Could not create SSL/TLS secure channel.” solved

When trying to establish a TLS connection, the above message was seen intermittently. Other messages included “The underlying connection was closed: The connection was closed unexpectedly.”

At the same time these apparent comms errors occurred, looking in the System event log showed a lot of Schannel EventCode 36888 with the message:

"The following fatal alert was generated: 80. The internal error state is 301."

The explanation for code 80 from http://blogs.msdn.com/b/kaushal/archive/2012/10/06/ssl-tls-alert-protocol-amp-the-alert-codes.aspx is:

An internal error unrelated to the peer or the correctness of the protocol makes it impossible to continue, such as a memory allocation failure. The error is not related to protocol. This message is always fatal.

The key to solving this was memory allocation failure, it was not the external system but internal memory pressure that was causing the problem. Fixing the memory issue also resolved the communications issues.

Unfortunately this is just one cause of this error message, other times it has turned out to be the external system in which case System.Net tracing could help:
https://msdn.microsoft.com/en-us/library/ty48b824%28v=vs.110%29.aspx

(At the time, one of the external systems had upgraded a version of Apache that had an issue in mod_proxy_http).

Apache Java HttpClient not re-using persistent connections (solved)

Currently trying to diagnose some .NET connection failures so I ported my code to Java to see if I could eliminate some causes as this won’t use SChannel (instead using JSSE).

To do this I chose the Apache HttpClient (version 4.3) – running multiple calls it seemed to be working but quite slowly. Wireshark revealed that it was doing a handshake every time. See multiple client hellos:

Wireshark-handshake

TCPView also showed multiple connections being established:

TCPView-lotsofconnections

Despite trying BasicHttpClientConnectionManager and PoolingHttpClientConnectionManager with a pool size of 1 it still wouldn’t reuse the connection. Keep-Alive headers were being sent by the server but as shown in the SSL diagnostics (using -Djavax.net.debug=all), the socket was still closed:

Keep-Alive: timeout=10, max=100, Connection: Keep-Alive]}
main, called close()
main, called closeInternal(true)
main, SEND TLSv1.1 ALERT: warning, description = close_notify

In my scenario, I expected the response from the server to only contain a location header and no body however I then noticed was the content-length was set to 20.

Solution

So the problem was that I was not fully consuming/reading the body of the response, doing so meant the socket could be re-used:

HttpEntity entity = response.getEntity();
// do something useful with the response body
// and ensure it is fully consumed otherwise connection is not reused
EntityUtils.consume(entity);

Now I get a much nicer looking wireshark trace!

Wireshark-connectionreused

Of course now I know the answer – I can also find it on stackoverflow: http://stackoverflow.com/questions/8200038/httpclient-4-x-connection-reuse-not-happening

Certificates MMC sucks – use powershell!

You can navigate your certificates by opening powershell and doing:

cd Cert:
dir
etc.

A dir of the “my” folder shows thumbprints first which is much more useful to me. The MMC snap-in doesn’t show a thumbprint column.

To find a certificate by thumbprint, do:

dir -recurse | where {$_.Thumbprint -eq “B8421CF9EC87413CB741064C4E798311”} | Format-List -property *