diff --git a/packages/redis-driver/.github/CONTRIBUTING.md b/packages/redis-driver/.github/CONTRIBUTING.md new file mode 100644 index 0000000000..5403c19e46 --- /dev/null +++ b/packages/redis-driver/.github/CONTRIBUTING.md @@ -0,0 +1,50 @@ +# Contributing to @vuestorefront/redis-driver +We love your input! We want to make contributing to this project as easy and transparent as possible, whether it's: + +- Reporting a bug +- Discussing the current state of the code +- Submitting a fix +- Proposing new features +- Becoming a maintainer + +## We Develop with Github +We use github to host code, to track issues and feature requests, as well as accept pull requests. + +## We Use [Git Flow](https://www.atlassian.com/git/tutorials/comparing-workflows/gitflow-workflow), So All Code Changes Happen Through Pull Requests +Pull requests are the best way to propose changes to the codebase (we use [Git Flow](https://www.atlassian.com/git/tutorials/comparing-workflows/gitflow-workflow)). We actively welcome your pull requests: + +1. Fork the repo and create your branch from `develop`. +2. If you've added code that should be tested, add tests. +3. If you've changed APIs, update the documentation. +4. Ensure the test suite passes. +5. Make sure your code lints. +6. Issue that pull request! + +## Any contributions you make will be under the MIT Software License +In short, when you submit code changes, your submissions are understood to be under the same [MIT License](http://choosealicense.com/licenses/mit/) that covers the project. Feel free to contact the maintainers if that's a concern. + +## Report bugs using Github's [issues](https://github.com/vuestorefront/redis-driver/issues) +We use GitHub issues to track public bugs. Report a bug by [opening a new issue](https://github.com/vuestorefront/redis-driver/issues/new); it's that easy! + +## Write bug reports with detail, background, and sample code +**Great Bug Reports** tend to have: + +- A quick summary and/or background +- Steps to reproduce + - Be specific! + - Give sample code if you can. +- What you expected would happen +- What actually happens +- The environment you're running the application +- Notes (possibly including why you think this might be happening, or stuff you tried that didn't work) + +People *love* thorough bug reports. I'm not even kidding. + +## Use a Consistent Coding Style +I'm again borrowing these from [AirBnB's Code Style](https://github.com/airbnb/javascript) + +* 2 spaces for indentation rather than tabs +* You can try running `npm run lint` for style unification + +## License +By contributing, you agree that your contributions will be licensed under its MIT License. diff --git a/packages/redis-driver/.github/ISSUE_TEMPLATE/1.bug-report.yml b/packages/redis-driver/.github/ISSUE_TEMPLATE/1.bug-report.yml new file mode 100644 index 0000000000..b1085031e2 --- /dev/null +++ b/packages/redis-driver/.github/ISSUE_TEMPLATE/1.bug-report.yml @@ -0,0 +1,79 @@ +name: "🐛 Bug report" +description: Report errors or unexpected behavior +labels: + - bug + - triage-needed +title: '[Bug]: ' +body: + - type: markdown + attributes: + value: | + Thanks for taking the time to fill out this bug report, please make sure to [search for existing issues](https://github.com/vuestorefront/redis-driver/issues) before filing a new one! + - type: textarea + id: whattoexpect + attributes: + label: Expected Behavior + placeholder: What were you expecting? + validations: + required: false + - type: textarea + id: whathappened + attributes: + label: Actual Behavior + placeholder: What happened instead?? + validations: + required: true + - type: textarea + id: solution + attributes: + label: Possible Solution + description: Also, if possible provide the information on how to implement the solution. + placeholder: Do you have any possible solution or fix for this bug? + validations: + required: false + - type: textarea + id: reproduce + attributes: + label: Steps to reproduce + description: Please provide detailed instructions on how to reproduce. + placeholder: How we can reproduce this bug? + validations: + required: false + - type: input + attributes: + label: What version of Magento 2 integration are you using? + description: 'For example: 1.0.0' + validations: + required: true + - type: input + attributes: + label: What version of Node.js are you using? + description: 'For example: 12.0.0' + validations: + required: true + - type: input + attributes: + label: What browser (and version) are you using? + description: 'For example: Chrome, Safari' + validations: + required: true + - type: input + attributes: + label: What operating system (and version) are you using? + description: 'For example: macOS, Windows' + validations: + required: true + - type: textarea + id: logs + attributes: + label: Relevant log output + description: Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks. + render: shell + - type: checkboxes + id: terms + attributes: + label: Code of Conduct + description: By submitting this issue, you agree to follow our [Code of Conduct](https://github.com/vuestorefront/redis-driver/blob/master/CODE_OF_CONDUCT.md) + options: + - label: I agree to follow this project's Code of Conduct + required: true diff --git a/packages/redis-driver/.github/ISSUE_TEMPLATE/2.documentation-issue.yml b/packages/redis-driver/.github/ISSUE_TEMPLATE/2.documentation-issue.yml new file mode 100644 index 0000000000..02124ce4ce --- /dev/null +++ b/packages/redis-driver/.github/ISSUE_TEMPLATE/2.documentation-issue.yml @@ -0,0 +1,31 @@ +name: "📚 Documentation Issue" +description: | + Report issues in our documentation +labels: + - documentation + - triage-needed +body: + - type: textarea + attributes: + label: Provide a description of requested docs changes + placeholder: Briefly describe which document needs to be corrected. + validations: + required: true + - type: checkboxes + id: fixthebug + attributes: + label: Able to fix / change the documentation? + description: Can you handle this change and create a Pull Request? + options: + - label: 'Yes' + required: false + - label: 'No' + required: false + - type: checkboxes + id: terms + attributes: + label: Code of Conduct + description: By submitting this issue, you agree to follow our [Code of Conduct](https://github.com/vuestorefront/redis-driver/blob/master/CODE_OF_CONDUCT.md) + options: + - label: I agree to follow this project's Code of Conduct + required: true diff --git a/packages/redis-driver/.github/ISSUE_TEMPLATE/3.feature-request.yml b/packages/redis-driver/.github/ISSUE_TEMPLATE/3.feature-request.yml new file mode 100644 index 0000000000..456a4afa84 --- /dev/null +++ b/packages/redis-driver/.github/ISSUE_TEMPLATE/3.feature-request.yml @@ -0,0 +1,40 @@ +name: "🚀 Feature Request" +description: Sugest a new feature request or improvement on the project +title: '[Feature]: ' +labels: + - feature + - enhancement + - triage-needed + +body: + - type: markdown + attributes: + value: | + Please, provide as many information, and knowledge so the feature can be correctly designed and developed. + - type: textarea + id: suggestion + attributes: + label: How the project can be improved? + description: What is the motivation for adding / enhancing this feature? Can you describe a concrete use case for this feature or why one of current ones should be enhanced. + placeholder: Describe the motivation or the concrete use case + validations: + required: true + - type: textarea + id: acceptcriterea + attributes: + label: What are the acceptance criteria? + description: List the acceptance criteria for this task in a form of a list. + value: '- [ ]' + - type: textarea + id: additionalinfo + attributes: + label: Additional information + description: If you think that any additional information would be useful please provide them here. + - type: checkboxes + id: terms + attributes: + label: Code of Conduct + description: By submitting this issue, you agree to follow our [Code of Conduct](https://github.com/vuestorefront/redis-driver/blob/master/CODE_OF_CONDUCT.md) + options: + - label: I agree to follow this project's Code of Conduct + required: true diff --git a/packages/redis-driver/.github/ISSUE_TEMPLATE/4.question.yml b/packages/redis-driver/.github/ISSUE_TEMPLATE/4.question.yml new file mode 100644 index 0000000000..d361317927 --- /dev/null +++ b/packages/redis-driver/.github/ISSUE_TEMPLATE/4.question.yml @@ -0,0 +1,28 @@ +name: "❓ Question / Basic Issue" +description: | + Do you have a question on the implementation or a basic issue +labels: + - triage-needed +body: + - type: markdown + attributes: + value: If you are not sure how something works or want discuss something just describe your doubts. + - type: textarea + attributes: + label: What is your question / Please describe your issue + validations: + required: true + - type: input + attributes: + label: What version of Magento 2 Integration are you using? + description: 'For example: 1.0.0' + validations: + required: true + - type: checkboxes + id: terms + attributes: + label: Code of Conduct + description: By submitting this issue, you agree to follow our [Code of Conduct](https://github.com/vuestorefront/vue-storefront/blob/master/CODE_OF_CONDUCT.md) + options: + - label: I agree to follow this project's Code of Conduct + required: true diff --git a/packages/redis-driver/.github/ISSUE_TEMPLATE/config.yml b/packages/redis-driver/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 0000000000..ccae31e286 --- /dev/null +++ b/packages/redis-driver/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,5 @@ +blank_issues_enabled: false +contact_links: + - name: Discord Chat + url: https://discord.vuestorefront.io/ + about: Ask questions and discuss with other Vue Storefront users in real time. diff --git a/packages/redis-driver/.github/PULL_REQUEST_TEMPLATE.md b/packages/redis-driver/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000000..fab5004390 --- /dev/null +++ b/packages/redis-driver/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,36 @@ + + +## Description + + +## Related Issue + + + + + +## Motivation and Context + + +## How Has This Been Tested? + + + + +## Screenshots (if appropriate): + +## Types of changes + +- [ ] Bug fix (non-breaking change which fixes an issue) +- [ ] New feature (non-breaking change which adds functionality) +- [ ] Breaking change (fix or feature that would cause existing functionality to change) + +## Checklist: + + +- [ ] My code follows the code style of this project. +- [ ] My change requires a change to the documentation. +- [ ] I have updated the documentation accordingly. +- [ ] I have read the **CONTRIBUTING** document. +- [ ] I have added tests to cover my changes. +- [ ] All new and existing tests passed. diff --git a/packages/redis-driver/.github/lock.yml b/packages/redis-driver/.github/lock.yml new file mode 100644 index 0000000000..4bd5b48a8a --- /dev/null +++ b/packages/redis-driver/.github/lock.yml @@ -0,0 +1,9 @@ +# Configuration for lock-threads - https://github.com/dessant/lock-threads +# disable lock bot for now +daysUntilLock: 3650 +exemptLabels: [] +lockLabel: false +lockComment: > + This thread has been automatically locked since there has not been + any recent activity after it was closed. Please open a new issue for + related bugs. diff --git a/packages/redis-driver/.github/stale.yml b/packages/redis-driver/.github/stale.yml new file mode 100644 index 0000000000..0ef631e003 --- /dev/null +++ b/packages/redis-driver/.github/stale.yml @@ -0,0 +1,66 @@ +# Configuration for probot-stale - https://github.com/probot/stale + +# Number of days of inactivity before an Issue or Pull Request becomes stale +# daysUntilStale: 60 + +# Number of days of inactivity before an Issue or Pull Request with the stale label is closed. +# Set to false to disable. If disabled, issues still need to be closed manually, but will remain marked as stale. +# daysUntilClose: 7 + +# Only issues or pull requests with all of these labels are check if stale. Defaults to `[]` (disabled) +onlyLabels: [] + +# Issues or Pull Requests with these labels will never be considered stale. Set to `[]` to disable +# exemptLabels: +# - backlog + +# Set to true to ignore issues in a project (defaults to false) +exemptProjects: false + +# Set to true to ignore issues in a milestone (defaults to false) +exemptMilestones: false + +# Set to true to ignore issues with an assignee (defaults to false) +exemptAssignees: false + +# Label to use when marking as stale +staleLabel: wontfix + +# Comment to post when marking as stale. Set to `false` to disable +# markComment: > +# This issue has been automatically marked as stale because it has not had +# recent activity. It will be closed if no further activity occurs. Thank you +# for your contributions. + +# Comment to post when removing the stale label. +# unmarkComment: > +# Your comment here. + +# Comment to post when closing a stale Issue or Pull Request. +# closeComment: > +# Your comment here. + +# Limit the number of actions per hour, from 1-30. Default is 30 +limitPerRun: 30 + +# Limit to only `issues` or `pulls` +# only: issues + +# Optionally, specify configuration settings that are specific to just 'issues' or 'pulls': +pulls: + daysUntilStale: 15 + daysUntilClose: 7 + markComment: > + This pull request has been automatically marked as stale. + It will be closed if no further activity occurs. + Thank you for your contributions. + +issues: + daysUntilStale: 30 + daysUntilClose: 7 + markComment: > + This issue has been automatically marked as stale. + It will be closed if no further activity occurs. + Thank you for your contributions. + exemptLabels: + - backlog diff --git a/packages/redis-driver/.github/workflows/assing-pr-to-author.yml b/packages/redis-driver/.github/workflows/assing-pr-to-author.yml new file mode 100644 index 0000000000..3cf7226c94 --- /dev/null +++ b/packages/redis-driver/.github/workflows/assing-pr-to-author.yml @@ -0,0 +1,14 @@ +name: PR to Author +on: + pull_request: + types: [opened, ready_for_review, edited, synchronize] + +jobs: + assignAuthor: + name: Assing + runs-on: ubuntu-latest + steps: + - uses: samspills/assign-pr-to-author@v1.0 + if: github.event_name == 'pull_request' && github.event.action == 'opened' + with: + repo-token: '${{ secrets.GITHUB_TOKEN }}' diff --git a/packages/redis-driver/.github/workflows/conventional-pr-name.yml b/packages/redis-driver/.github/workflows/conventional-pr-name.yml new file mode 100644 index 0000000000..895c766f68 --- /dev/null +++ b/packages/redis-driver/.github/workflows/conventional-pr-name.yml @@ -0,0 +1,21 @@ +name: Commitlint PR Title +on: + pull_request: + types: ['opened', 'edited', 'reopened', 'synchronize'] + +jobs: + lint: + name: Validate PR Title (conventional-commit) + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v1 + + - name: Setup node + uses: actions/setup-node@v2 + with: + node-version: "16" + + - name: Install Dependencies + run: yarn + + - uses: JulienKode/pull-request-name-linter-action@v0.2.0 diff --git a/packages/redis-driver/.github/workflows/publish-npm.yml b/packages/redis-driver/.github/workflows/publish-npm.yml new file mode 100644 index 0000000000..448637431f --- /dev/null +++ b/packages/redis-driver/.github/workflows/publish-npm.yml @@ -0,0 +1,29 @@ +name: Publish Packages on NPM +on: + workflow_dispatch: + inputs: + npmTag: + description: 'NPM Tag' + required: true + default: 'latest' + +jobs: + publishing: + name: Package Publishing + runs-on: ubuntu-latest + env: + NPM_TOKEN: ${{ secrets.NPM_TOKEN }} + steps: + - name: Checkout code + uses: actions/checkout@v2 + + - name: Setup node + uses: actions/setup-node@v2 + with: + node-version: "16" + registry-url: "https://registry.npmjs.org/" + scope: "@vue-storefront" + - run: echo "" >> .npmrc && echo "@vue-storefront:registry=https://registry.npmjs.org/" >> .npmrc + - run: yarn publish:driver "${{ github.event.inputs.npmTag }}" "$NODE_AUTH_TOKEN" + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} diff --git a/packages/redis-driver/.gitignore b/packages/redis-driver/.gitignore new file mode 100644 index 0000000000..8ab847e7c1 --- /dev/null +++ b/packages/redis-driver/.gitignore @@ -0,0 +1,105 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* + +# Diagnostic reports (https://nodejs.org/api/report.html) +report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage +*.lcov + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules/ +jspm_packages/ + +# TypeScript v1 declaration files +typings/ + +# TypeScript cache +*.tsbuildinfo + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Microbundle cache +.rpt2_cache/ +.rts2_cache_cjs/ +.rts2_cache_es/ +.rts2_cache_umd/ + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variables file +.env +.env.test + +# parcel-bundler cache (https://parceljs.org/) +.cache + +# Next.js build output +.next + +# Nuxt.js build / generate output +.nuxt +dist + +# Gatsby files +.cache/ +# Comment in the public line in if your project uses Gatsby and *not* Next.js +# https://nextjs.org/blog/next-9-1#public-directory-support +# public + +# vuepress build output +.vuepress/dist + +# Serverless directories +.serverless/ + +# FuseBox cache +.fusebox/ + +# DynamoDB Local files +.dynamodb/ + +# TernJS port file +.tern-port +.idea diff --git a/packages/redis-driver/CHANGELOG.md b/packages/redis-driver/CHANGELOG.md new file mode 100644 index 0000000000..747b60f1b6 --- /dev/null +++ b/packages/redis-driver/CHANGELOG.md @@ -0,0 +1,7 @@ +# 2.0.0 + +* feat: `redis.maxRetriesPerRequest` set to `3` by default to use renderer sooner if Redis is temporairly down + +# 1.0.1 + +* fix: change entry point ([#3](https://github.com/vuestorefront/redis-driver/pull/3)) diff --git a/packages/redis-driver/LICENSE b/packages/redis-driver/LICENSE new file mode 100644 index 0000000000..59af69f519 --- /dev/null +++ b/packages/redis-driver/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2022 Vue Storefront + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/packages/redis-driver/README.md b/packages/redis-driver/README.md new file mode 100644 index 0000000000..485cd35d87 --- /dev/null +++ b/packages/redis-driver/README.md @@ -0,0 +1,22 @@ +
+ Alokai logo +
+ +--------- + +### Stay connected + +[![GitHub Repo stars](https://img.shields.io/github/stars/vuestorefront/vue-storefront?style=social)](https://github.com/vuestorefront/vue-storefront) +[![Twitter Follow](https://img.shields.io/twitter/follow/vuestorefront?style=social)](https://twitter.com/vuestorefront) +[![YouTube Channel Subscribers](https://img.shields.io/youtube/channel/subscribers/UCkm1F3Cglty3CE1QwKQUhhg?style=social)](https://www.youtube.com/c/VueStorefront) +[![Discord](https://img.shields.io/discord/770285988244750366?label=join%20discord&logo=Discord&logoColor=white)](https://discord.vuestorefront.io) + +# Redis cache driver for Alokai + +This package is a Redis driver for the Server-Side Rendering (SSR) Cache in Alokai. + +Follow the [Installation](https://docs.vuestorefront.io/v2/integrations/redis-cache.html) guide to install and configure it and [Server Side Rendering Cache](https://docs.vuestorefront.io/v2/performance/ssr-cache.html) document to learn how it works and how to use it in your Alokai project. diff --git a/packages/redis-driver/package.json b/packages/redis-driver/package.json new file mode 100644 index 0000000000..0948ca239f --- /dev/null +++ b/packages/redis-driver/package.json @@ -0,0 +1,21 @@ +{ + "name": "@vue-storefront/redis-cache", + "version": "2.0.0", + "description": "Redis driver for the SSR cache in Vue Storefront 2", + "license": "MIT", + "main": "src/index.js", + "scripts": { + "publish:driver": "node ./scripts/publishDriver.js" + }, + "dependencies": { + "redis-tag-cache": "^1.2.1" + }, + "files": [ + "src/index.js" + ], + "engines": { + "node": ">=12.x.x", + "yarn": "1.x.x||>=3.x.x" + }, + "packageManager": "yarn@1.22.15" +} diff --git a/packages/redis-driver/scripts/publishDriver.js b/packages/redis-driver/scripts/publishDriver.js new file mode 100644 index 0000000000..1d2bb55543 --- /dev/null +++ b/packages/redis-driver/scripts/publishDriver.js @@ -0,0 +1,11 @@ +const path = require('path'); +const { publishPackages } = require('./lib/publishNpm'); + +const myArgs = process.argv.slice(2); +const labels = myArgs[0]; + +publishPackages(path.join(process.cwd()), labels) + .then(console.log) + .catch((e) => { + console.error(e); + }); diff --git a/packages/redis-driver/src/index.js b/packages/redis-driver/src/index.js new file mode 100644 index 0000000000..b544aba6ca --- /dev/null +++ b/packages/redis-driver/src/index.js @@ -0,0 +1,119 @@ +import Redis from 'redis-tag-cache'; + +const defaultRedisOptions = { + maxRetriesPerRequest: 3 +}; + +export default function RedisCache (opt) { + const options = { + ...opt, + redis: { + ...opt?.redis, + ...defaultRedisOptions + } + }; + const client = new Redis(options); + + return { + async invoke({ route, render, getTags }) { + let key = `page:${ route }`; + let shouldCache = true; + + if ( + options.queryParamFilter?.denyList && + options.queryParamFilter?.allowList + ) { + + /* + allowList and denyList contain query params that could affect the content of the page. + Any other params that don't exist in deny/allowList can be stripped as they do not affect the content of the page (e.g. gclid). + + Examples: + sale/april-catalogue/up-to-50-off?sc_src=email_3757321&sc_lid=272735070&sc_uid=zNKj3A7HFD - Cache but strip all except allowList + term=white+shirt&sort=price_ascending&page=2 - Only allowListed params - cache and keep allowList + search?term=dress&sort=price_ascending&page=1&itemsPerPage=100 - Do not cache, denyList item exists + */ + const cleanParams = []; + const urlParts = route.split('?'); + + // eslint-disable-next-line eqeqeq + if (urlParts.length == 2) { + const params = urlParts[1].split('&'); + + for (const param of params) { + const paramKey = param.split('=')[0]; + // eslint-disable-next-line max-depth + if ( + // Do not cache: denyListed param exists (stop processing further params) + options.queryParamFilter.denyList.includes(paramKey) + ) { + shouldCache = false; + break; + } + // add any allowList params to cleanParams, ignore any other params + // eslint-disable-next-line max-depth + if (options.queryParamFilter.allowList.includes(paramKey)) { + cleanParams.push(param); + } + } + } + + key = `page:${urlParts[0]}${ + cleanParams.length ? '?' : '' + }${cleanParams.join('&')}`; + + // console.log(`Original route: ${route}\nkey ${shouldCache ? "is" : "is not"} cacheable`); + + } + + if (shouldCache) { + const cachedResponse = await client.get(key); + + if (cachedResponse) { + return cachedResponse; + } + } + + const content = await render(); + const tags = getTags(); + + if (!tags.length) { + return content; + } + + // We could add "await" here, but saving content in cache doesn't have to block the request + if (shouldCache) { + client.set( + key, + content, + tags + ); + } + return content; + }, + + invalidate({ tags }) { + const clearAll = tags.includes('*'); + + if (!clearAll) { + return client.invalidate(...tags); + } + + return new Promise((resolve, reject) => { + const prefix = `${options.redis.keyPrefix || ''}tags:`; + const stream = client.redis.scanStream({ match: `${prefix}*` }); + + const tags = []; + + stream.on('data', rawTags => tags.push(...rawTags.map(tag => tag.replace(prefix, '')))); + stream.on('end', async () => { + if (tags.length) { + await client.invalidate(...tags); + } + resolve(); + }); + stream.on('error', reject); + }); + } + }; +} diff --git a/yarn.lock b/yarn.lock index a26add8a02..c35487b287 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5889,6 +5889,11 @@ cloneable-readable@^1.0.0: process-nextick-args "^2.0.0" readable-stream "^2.3.5" +cluster-key-slot@^1.1.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz#88ddaa46906e303b5de30d3153b7d9fe0a0c19ac" + integrity sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA== + cmd-shim@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/cmd-shim/-/cmd-shim-5.0.0.tgz#8d0aaa1a6b0708630694c4dbde070ed94c707724" @@ -7060,6 +7065,11 @@ delegates@^1.0.0: resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" integrity sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ== +denque@^1.1.0: + version "1.5.1" + resolved "https://registry.yarnpkg.com/denque/-/denque-1.5.1.tgz#07f670e29c9a78f8faecb2566a1e2c11929c5cbf" + integrity sha512-XwE+iZ4D6ZUB7mfYRMb5wByE8L74HCn30FBN7sWnXksWc1LO1bPDl67pBR9o/kC4z/xSNAwkMYcGgqDV3BE3Hw== + depd@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df" @@ -10103,6 +10113,23 @@ invert-kv@^3.0.0: resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-3.0.1.tgz#a93c7a3d4386a1dc8325b97da9bb1620c0282523" integrity sha512-CYdFeFexxhv/Bcny+Q0BfOV+ltRlJcd4BBZBYFX/O0u4npJrgZtIcjokegtiSMAvlMTJ+Koq0GBCc//3bueQxw== +ioredis@^4.0.0: + version "4.28.5" + resolved "https://registry.yarnpkg.com/ioredis/-/ioredis-4.28.5.tgz#5c149e6a8d76a7f8fa8a504ffc85b7d5b6797f9f" + integrity sha512-3GYo0GJtLqgNXj4YhrisLaNNvWSNwSS2wS4OELGfGxH8I69+XfNdnmV1AyN+ZqMh0i7eX+SWjrwFKDBDgfBC1A== + dependencies: + cluster-key-slot "^1.1.0" + debug "^4.3.1" + denque "^1.1.0" + lodash.defaults "^4.2.0" + lodash.flatten "^4.4.0" + lodash.isarguments "^3.1.0" + p-map "^2.1.0" + redis-commands "1.7.0" + redis-errors "^1.2.0" + redis-parser "^3.0.0" + standard-as-callback "^2.1.0" + ip-regex@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/ip-regex/-/ip-regex-2.1.0.tgz#fa78bf5d2e6913c911ce9f819ee5146bb6d844e9" @@ -11668,11 +11695,26 @@ lodash.debounce@^4.0.8: resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" integrity sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow== +lodash.defaults@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/lodash.defaults/-/lodash.defaults-4.2.0.tgz#d09178716ffea4dde9e5fb7b37f6f0802274580c" + integrity sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ== + +lodash.flatten@^4.4.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/lodash.flatten/-/lodash.flatten-4.4.0.tgz#f31c22225a9632d2bbf8e4addbef240aa765a61f" + integrity sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g== + lodash.get@^4, lodash.get@^4.4.2: version "4.4.2" resolved "https://registry.yarnpkg.com/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99" integrity sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ== +lodash.isarguments@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz#2f573d85c6a24289ff00663b491c1d338ff3458a" + integrity sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg== + lodash.isequal@^4.5.0: version "4.5.0" resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0" @@ -14917,6 +14959,30 @@ redeyed@~2.1.0: dependencies: esprima "~4.0.0" +redis-commands@1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/redis-commands/-/redis-commands-1.7.0.tgz#15a6fea2d58281e27b1cd1acfb4b293e278c3a89" + integrity sha512-nJWqw3bTFy21hX/CPKHth6sfhZbdiHP6bTawSgQBlKOVRG7EZkfHbbHwQJnrE4vsQf0CMNE+3gJ4Fmm16vdVlQ== + +redis-errors@^1.0.0, redis-errors@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/redis-errors/-/redis-errors-1.2.0.tgz#eb62d2adb15e4eaf4610c04afe1529384250abad" + integrity sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w== + +redis-parser@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/redis-parser/-/redis-parser-3.0.0.tgz#b66d828cdcafe6b4b8a428a7def4c6bcac31c8b4" + integrity sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A== + dependencies: + redis-errors "^1.0.0" + +redis-tag-cache@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/redis-tag-cache/-/redis-tag-cache-1.2.1.tgz#07d6e1f945d9d5c8186602129cb10573167d7534" + integrity sha512-0F+rLtoIkz4NOWGt9k3qaPcbpvr6+wcEC9aWV78newMKTRN/nIYHgvfyO1Q0ySEepiEYbqj9DhjvQ4CUAtT9/g== + dependencies: + ioredis "^4.0.0" + reduce-css-calc@^2.1.8: version "2.1.8" resolved "https://registry.npmjs.org/reduce-css-calc/-/reduce-css-calc-2.1.8.tgz#7ef8761a28d614980dc0c982f772c93f7a99de03" @@ -16060,6 +16126,11 @@ stack-utils@^2.0.3: dependencies: escape-string-regexp "^2.0.0" +standard-as-callback@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/standard-as-callback/-/standard-as-callback-2.1.0.tgz#8953fc05359868a77b5b9739a665c5977bb7df45" + integrity sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A== + static-extend@^0.1.1: version "0.1.2" resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6"