<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Dave Cozens</title>
    <description>The latest articles on DEV Community by Dave Cozens (@davecozens).</description>
    <link>https://dev.to/davecozens</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F419426%2F26f6ad60-9f3f-4747-9df8-5f62a4bf4a1d.jpeg</url>
      <title>DEV Community: Dave Cozens</title>
      <link>https://dev.to/davecozens</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/davecozens"/>
    <language>en</language>
    <item>
      <title>Caching XHR Responses in Local Storage</title>
      <dc:creator>Dave Cozens</dc:creator>
      <pubDate>Tue, 12 Oct 2021 12:23:49 +0000</pubDate>
      <link>https://dev.to/davecozens/caching-xhr-responses-in-local-storage-3g33</link>
      <guid>https://dev.to/davecozens/caching-xhr-responses-in-local-storage-3g33</guid>
      <description>&lt;p&gt;So, I've been working on my site recently - &lt;a href="https://uktidetimes.com/"&gt;https://uktidetimes.com/&lt;/a&gt; - and it occurred to me that since I'm serving content that only changes once a day, there's really no reason for the same user to repeatedly hit the service. &lt;/p&gt;

&lt;p&gt;I was already using Axios for my XHR requests, so I've put together an NPM module that wraps Axios but adds additional caching capabilities using local storage in the browser.&lt;/p&gt;

&lt;p&gt;There's two primary benefits to this: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It reduces the amount of traffic to my API (which is running on AWS Lambda) - therefore reducing costs.&lt;/li&gt;
&lt;li&gt;It improves load time for the user if they've already views this data&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://www.npmjs.com/package/xhr-cache-with-ttl"&gt;https://www.npmjs.com/package/xhr-cache-with-ttl&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As a coder, I obviously want to do as little typing as possible so I wanted to take the approach of wrapping a known-awesome HTTP request library (in this case Axios) because most of the work has been done already. Nobody wants to reinvent that wheel today, thank you.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function xhrCache(method, url, options = {}) {
    return new Promise(function (resolve, reject) {
        axios[method](url, options).then((res) =&amp;gt; {
            resolve(res)
        })
    })
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nice and easy. Axios wrapped in a promise, passing through the method, URL and options attributes that it already uses.&lt;/p&gt;

&lt;p&gt;This just left me to throw together a basic caching mechanism.&lt;/p&gt;

&lt;p&gt;I decided that I'd create two keys in local storage per cached request - one for the metadata (TTL and timestamp) and one for the response. This avoids a potentially heavy deserialisation cost of expired cache items.&lt;/p&gt;

&lt;p&gt;I'm using the URL of the request as part of the key in local storage. This helps with diagnosing any issues but there's an argument for hashing it for brevity (and differentiating more complex requests). Maybe for another day.&lt;/p&gt;

&lt;p&gt;The flow of the function is nice and simple.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if (cache exists &amp;amp;&amp;amp; cache not expired){
    return cached content
} else {
    fetch content using Axios
    cache content
    return content
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The whole thing comes in at less than 100 lines of code, and it's open source so feel free to make off with it :)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/davecozens/xhr-cache-with-ttl"&gt;https://github.com/davecozens/xhr-cache-with-ttl&lt;/a&gt; &lt;/p&gt;

&lt;h1&gt;
  
  
  How to use it
&lt;/h1&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const result = await xhrCache("get", url, { ttl: 600 })
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
    </item>
    <item>
      <title>Triggering Github workflows from other repositories, now with locking</title>
      <dc:creator>Dave Cozens</dc:creator>
      <pubDate>Fri, 06 Aug 2021 11:17:15 +0000</pubDate>
      <link>https://dev.to/davecozens/triggering-github-workflows-from-other-repositories-now-with-locking-3c5f</link>
      <guid>https://dev.to/davecozens/triggering-github-workflows-from-other-repositories-now-with-locking-3c5f</guid>
      <description>&lt;p&gt;OK, so we live in a world of automation and GitHub Actions, because nobody wants to deploy things themselves, right?&lt;/p&gt;

&lt;p&gt;Sometimes you have multiple repositories, because code separation is fun and we need to be able trigger downstream builds in a different repository using github actions.&lt;/p&gt;

&lt;p&gt;Easy, you say? Comes out of the box with GitHub Actions...&lt;/p&gt;

&lt;p&gt;Repository A:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...
    - name: Trigger my downstream workflow
        run: |
          curl -XPOST -u "${{ secrets.GIT_CREDENTIALS }}" -H "Accept:application/vnd.github" -H "Content-Type:application/json" https://api.github.com/repos/path/to/workflow.yml/dispatches --data '{"ref": "main" }'
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Repository X:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;name: Deploy Repo X
on:
  workflow_dispatch:
    inputs:
      source:
        description: 'Source of event'
        required: false
        default: 'No source specified'
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;...and off we go. Easy peasy.&lt;/p&gt;

&lt;p&gt;But there's a downside here. Let's say we've got multiple repositories that all need to do the same thing. If any of Repos A, B, C &amp;amp; D change they need to trigger a build of Repo X. &lt;/p&gt;

&lt;p&gt;Great. No problemo.&lt;/p&gt;

&lt;p&gt;However, if all 4 repos change at once, we get 4 builds. That'll tie up the build system for an hour. Horrible log jam. Angry developers. The works. And GitHub don't provide any kind of build throttling (are you listening GitHub? ARE YOU???)&lt;/p&gt;

&lt;p&gt;What we need is a way to prevent multiple repos from submitting a new pending job if one of its siblings had recently done the same thing.&lt;/p&gt;

&lt;p&gt;Sounds like a job for Redis (he said with the benefit of hindsight).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SET buildlock 1 NX EX 180
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;enables us to set a buildlock key in Redis with an expiry of 3 minutes. The important thing here is that if the key is successfully set, Redis returns "OK", otherwise "(nil)".&lt;/p&gt;

&lt;p&gt;So, without further ado, here's a way of only firing workflows on an upstream repo if &lt;em&gt;something else&lt;/em&gt; hasn't recently done so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;name: Update components
on:
  push:
    branches:
      - main
jobs:
  TriggerPlatformDeploy:
    runs-on: ubuntu-latest
    timeout-minutes: 20
    env:
      ENVIRONMENT: "dev"
    steps:
      - name: Install redis CLI
        run: |
          sudo apt-get install redis-tools -y
      - name: Check for recent push lock
        run: |
          didSet=$(redis-cli -a ${{ secrets.REDIS_TOKEN }} -h ${{ secrets.REDIS_URL }} -p$ {{ secrets.REDIS_PORT }} --no-auth-warning SET buildlock 1 NX EX 180)
          echo "didSet=$(echo $didSet)" &amp;gt;&amp;gt; $GITHUB_ENV
      - name: Trigger workflow if not locked
        if: env.didSet == 'OK'
        run: |
          curl -XPOST -u "${{ secrets.GIT_CREDENTIALS }}" -H "Accept:application/vnd.github" -H "Content-Type:application/json" https://api.github.com/repos/path/to/workflow.yml/dispatches --data '{"ref": "main" }'
      - name: Workflow is locked
        if: env.didSet != 'OK'
        run: |
          echo Suppressing build trigger because another repo has triggered within 3 minutes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>github</category>
      <category>redis</category>
      <category>devops</category>
    </item>
  </channel>
</rss>
