Skip to content

Commit f65500a

Browse files
authored
feat: sports and hobbies revalidate api DEVOPS-537 (#353)
* feat: sports and hobbies revalidate api DEVOPS-537
1 parent 035042a commit f65500a

8 files changed

Lines changed: 248 additions & 52 deletions

File tree

apps/hobbies-helsinki/.env.local.example

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ NEXT_PUBLIC_LINKEDEVENTS_EVENT_ENDPOINT="https://api.hel.fi/linkedevents/v1/even
44
NEXT_PUBLIC_APP_ORIGIN="http://localhost:3000"
55
NEXT_PUBLIC_IMAGE_PROXY_URL="https://images.weserv.nl/?w=1024&url="
66
NEXT_PUBLIC_DEBUG="true"
7-
NEXT_PUBLIC_DEFAULT_ISR_REVALIDATE_SECONDS=10
7+
NEXT_PUBLIC_DEFAULT_ISR_REVALIDATE_SECONDS=0
88
SENTRY_AUTH_TOKEN=
99
NEXT_PUBLIC_SENTRY_DSN=
1010
NEXT_PUBLIC_SENTRY_ENVIRONMENT="develop"
@@ -27,4 +27,6 @@ NEXTJS_DEBUG_I18N="true"
2727
NEXT_PUBLIC_ALLOW_UNAUTHORIZED_REQUESTS="true"
2828
DOCKER_BUILDKIT="true"
2929
NEXT_PUBLIC_SHOW_SIMILAR_EVENTS="true"
30-
NEXT_PUBLIC_SHOW_ENROLMENT_STATUS_IN_CARD_DETAILS="false"
30+
NEXT_PUBLIC_SHOW_ENROLMENT_STATUS_IN_CARD_DETAILS="false"
31+
SKIP_BUILD_STATIC_GENERATION=1
32+
REVALIDATE_TOKEN="revalidate_token"

apps/hobbies-helsinki/src/domain/app/AppConfig.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,12 @@ class AppConfig {
102102
);
103103
}
104104

105+
// no revalidation
106+
// https://nextjs.org/docs/pages/building-your-application/data-fetching/incremental-static-regeneration#on-demand-revalidation
107+
if (value < 1) {
108+
return false;
109+
}
110+
105111
return value;
106112
}
107113

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
// Next.js API route support: https://nextjs.org/docs/api-routes/introduction
2+
import {
3+
getAllArticles,
4+
getAllPages,
5+
APP_LANGUAGES,
6+
} from '@events-helsinki/components';
7+
import type { NextApiRequest, NextApiResponse } from 'next';
8+
import { hobbiesApolloClient } from '../../domain/clients/hobbiesApolloClient';
9+
import { staticGenerationLogger } from '../../logger';
10+
11+
// remove duplicates from array
12+
function uniqBySetWithArrayFrom<T>(array: T[]): T[] {
13+
return Array.from(new Set(array));
14+
}
15+
16+
export default async function handler(
17+
req: NextApiRequest,
18+
res: NextApiResponse
19+
) {
20+
let customUri = '';
21+
22+
// only POST allowed
23+
if (req.method !== 'POST') {
24+
return res.status(405).send('Only POST requests allowed');
25+
}
26+
27+
// Check for secret to confirm this is a valid request
28+
if (req.body.secret !== process.env.REVALIDATE_TOKEN) {
29+
return res.status(401).json({ message: 'Invalid token' });
30+
}
31+
if (req.body.uri) {
32+
customUri = req.body.uri;
33+
}
34+
35+
try {
36+
if (customUri === '') {
37+
// get all articles and pages
38+
const pages = [
39+
...(await getAllArticles(hobbiesApolloClient)),
40+
...(await getAllPages(hobbiesApolloClient)),
41+
].map((pageInfo) => {
42+
return pageInfo.uri.replace(/\/$/, '');
43+
});
44+
45+
// root pages
46+
for (const lng of APP_LANGUAGES) {
47+
pages.push('/' + lng);
48+
}
49+
50+
_revalidateAll(res, pages).catch((err) => {
51+
staticGenerationLogger.error(`Error during _revalidateAll`, err);
52+
});
53+
} else {
54+
_revalidate(res, customUri).catch((err) => {
55+
staticGenerationLogger.error(
56+
`Error during _revalidate ${customUri}`,
57+
err
58+
);
59+
});
60+
}
61+
return res.status(200).json({ revalidatetrigger: true });
62+
} catch (err) {
63+
// If there was an error, Next.js will continue
64+
// to show the last successfully generated page
65+
return res.status(500).send('Error revalidating');
66+
}
67+
}
68+
69+
// revalidate all pages one by one
70+
async function _revalidateAll(res: NextApiResponse, pages: string[]) {
71+
for (const page of uniqBySetWithArrayFrom(pages)) {
72+
await _revalidate(res, page);
73+
}
74+
}
75+
76+
// revalidate a page
77+
// return the uri if revalidation failed
78+
async function _revalidate(res: NextApiResponse, uri: string) {
79+
try {
80+
const _uri = uri.replace(/\/$/, '');
81+
if (_uri.length < 1) return null;
82+
83+
staticGenerationLogger.info(`Revalidate a page: ${uri}`);
84+
await res.revalidate(_uri);
85+
} catch (err) {
86+
staticGenerationLogger.error(`Error while revalidate a page: ${uri}`, err);
87+
return uri;
88+
}
89+
return null;
90+
}

apps/sports-helsinki/.env.local.example

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ NEXT_PUBLIC_LINKEDEVENTS_EVENT_ENDPOINT="https://api.hel.fi/linkedevents/v1/even
44
NEXT_PUBLIC_APP_ORIGIN="http://localhost:3000"
55
NEXT_PUBLIC_IMAGE_PROXY_URL="https://images.weserv.nl/?w=1024&url="
66
NEXT_PUBLIC_DEBUG="true"
7-
NEXT_PUBLIC_DEFAULT_ISR_REVALIDATE_SECONDS=10
7+
NEXT_PUBLIC_DEFAULT_ISR_REVALIDATE_SECONDS=0
88
SENTRY_AUTH_TOKEN=
99
NEXT_PUBLIC_SENTRY_DSN=
1010
NEXT_PUBLIC_SENTRY_ENVIRONMENT="develop"
@@ -30,3 +30,5 @@ NEXT_PUBLIC_SHOW_SIMILAR_EVENTS="true"
3030
NEXT_PUBLIC_SHOW_SIMILAR_VENUES="true"
3131
NEXT_PUBLIC_SHOW_VENUES_UPCOMING_EVENTS="true"
3232
NEXT_PUBLIC_SHOW_ENROLMENT_STATUS_IN_CARD_DETAILS="false"
33+
SKIP_BUILD_STATIC_GENERATION=1
34+
REVALIDATE_TOKEN="revalidate_token"

apps/sports-helsinki/src/domain/app/AppConfig.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,12 @@ class AppConfig {
102102
);
103103
}
104104

105+
// no revalidation
106+
// https://nextjs.org/docs/pages/building-your-application/data-fetching/incremental-static-regeneration#on-demand-revalidation
107+
if (value < 1) {
108+
return false;
109+
}
110+
105111
return value;
106112
}
107113

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
// Next.js API route support: https://nextjs.org/docs/api-routes/introduction
2+
import {
3+
getAllArticles,
4+
getAllPages,
5+
APP_LANGUAGES,
6+
} from '@events-helsinki/components';
7+
import type { NextApiRequest, NextApiResponse } from 'next';
8+
import { sportsApolloClient } from '../../domain/clients/sportsApolloClient';
9+
import { staticGenerationLogger } from '../../logger';
10+
11+
// remove duplicates from array
12+
function uniqBySetWithArrayFrom<T>(array: T[]): T[] {
13+
return Array.from(new Set(array));
14+
}
15+
16+
export default async function handler(
17+
req: NextApiRequest,
18+
res: NextApiResponse
19+
) {
20+
let customUri = '';
21+
22+
// only POST allowed
23+
if (req.method !== 'POST') {
24+
return res.status(405).send('Only POST requests allowed');
25+
}
26+
27+
// Check for secret to confirm this is a valid request
28+
if (req.body.secret !== process.env.REVALIDATE_TOKEN) {
29+
return res.status(401).json({ message: 'Invalid token' });
30+
}
31+
if (req.body.uri) {
32+
customUri = req.body.uri;
33+
}
34+
35+
try {
36+
if (customUri === '') {
37+
// get all articles and pages
38+
const pages = [
39+
...(await getAllArticles(sportsApolloClient)),
40+
...(await getAllPages(sportsApolloClient)),
41+
].map((pageInfo) => {
42+
return pageInfo.uri.replace(/\/$/, '');
43+
});
44+
45+
// root pages
46+
for (const lng of APP_LANGUAGES) {
47+
pages.push('/' + lng);
48+
}
49+
50+
_revalidateAll(res, pages).catch((err) => {
51+
staticGenerationLogger.error(`Error during _revalidateAll`, err);
52+
});
53+
} else {
54+
_revalidate(res, customUri).catch((err) => {
55+
staticGenerationLogger.error(
56+
`Error during _revalidate ${customUri}`,
57+
err
58+
);
59+
});
60+
}
61+
return res.status(200).json({ revalidatetrigger: true });
62+
} catch (err) {
63+
// If there was an error, Next.js will continue
64+
// to show the last successfully generated page
65+
return res.status(500).send('Error revalidating');
66+
}
67+
}
68+
69+
// revalidate all pages one by one
70+
async function _revalidateAll(res: NextApiResponse, pages: string[]) {
71+
for (const page of uniqBySetWithArrayFrom(pages)) {
72+
await _revalidate(res, page);
73+
}
74+
}
75+
76+
// revalidate a page
77+
// return the uri if revalidation failed
78+
async function _revalidate(res: NextApiResponse, uri: string) {
79+
try {
80+
const _uri = uri.replace(/\/$/, '');
81+
if (_uri.length < 1) return null;
82+
83+
staticGenerationLogger.info(`Revalidate a page: ${uri}`);
84+
await res.revalidate(_uri);
85+
} catch (err) {
86+
staticGenerationLogger.error(`Error while revalidate a page: ${uri}`, err);
87+
return uri;
88+
}
89+
return null;
90+
}

azure-pipelines-harrastukset-review.yml

Lines changed: 24 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -8,46 +8,46 @@
88
trigger: none
99

1010
# Pull request (PR) triggers cause a pipeline to run whenever a pull request is
11-
# opened with one of the specified target branches, or when updates are made to
11+
# opened with one of the specified target branches, or when updates are made to
1212
# such a pull request.
1313
#
14-
# GitHub creates a new ref when a pull request is created. The ref points to a
15-
# merge commit, which is the merged code between the source and target branches
14+
# GitHub creates a new ref when a pull request is created. The ref points to a
15+
# merge commit, which is the merged code between the source and target branches
1616
# of the pull request.
1717
#
18-
# Opt out of pull request validation
18+
# Opt out of pull request validation
1919
pr:
2020
# PR target branch
2121
branches:
2222
include:
23-
- main
23+
- main
2424
paths:
2525
include:
26-
- 'apps/hobbies-helsinki/**'
27-
- 'packages/**'
28-
- 'package.json'
29-
- 'yarn.lock'
30-
- '.yarnrc.yml'
31-
- '*.base.json'
32-
- '*.base.js'
33-
- '.prettier*.*'
34-
- 'azure-pipelines-harrastukset-review.yml'
35-
- 'Dockerfile'
36-
- '*.Dockerfile'
37-
- 'docker-compose.yml'
38-
- 'docker-compose.*.yml'
39-
- '!**/README.md'
26+
- 'apps/hobbies-helsinki/**'
27+
- 'packages/**'
28+
- 'package.json'
29+
- 'yarn.lock'
30+
- '.yarnrc.yml'
31+
- '*.base.json'
32+
- '*.base.js'
33+
- '.prettier*.*'
34+
- 'azure-pipelines-harrastukset-review.yml'
35+
- 'Dockerfile'
36+
- '*.Dockerfile'
37+
- 'docker-compose.yml'
38+
- 'docker-compose.*.yml'
39+
- '!**/README.md'
4040

4141
# By default, use self-hosted agents
4242
pool: Default
4343

4444
resources:
4545
repositories:
46-
# Azure DevOps repository
47-
- repository: harrastukset-pipelines
48-
type: git
49-
# Azure DevOps project/repository
50-
name: harrastukset/harrastukset-pipelines
46+
# Azure DevOps repository
47+
- repository: harrastukset-pipelines
48+
type: git
49+
# Azure DevOps project/repository
50+
name: harrastukset/harrastukset-pipelines
5151

5252
extends:
5353
# Filename in Azure DevOps Repository (note possible -ui or -api)

azure-pipelines-liikunta-review.yml

Lines changed: 25 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2,52 +2,52 @@
22
# Review pipeline. Run build and deploy for Platta test environments.
33
# Pipeline runs different tests e.g. unittest and browser tests.
44
#
5-
# Continuous integration (CI) triggers cause a pipeline to run whenever you push
5+
# Continuous integration (CI) triggers cause a pipeline to run whenever you push
66
# an update to the specified branches or you push specified tags.
77
# only PR trigger pipeline
88
trigger: none
99

1010
# Pull request (PR) triggers cause a pipeline to run whenever a pull request is
11-
# opened with one of the specified target branches, or when updates are made to
11+
# opened with one of the specified target branches, or when updates are made to
1212
# such a pull request.
1313
#
14-
# GitHub creates a new ref when a pull request is created. The ref points to a
15-
# merge commit, which is the merged code between the source and target branches
14+
# GitHub creates a new ref when a pull request is created. The ref points to a
15+
# merge commit, which is the merged code between the source and target branches
1616
# of the pull request.
1717
#
18-
# Opt out of pull request validation
18+
# Opt out of pull request validation
1919
pr:
2020
# PR target branch
2121
branches:
2222
include:
23-
- main
23+
- main
2424
paths:
2525
include:
26-
- 'apps/sports-helsinki/**'
27-
- 'packages/**'
28-
- 'package.json'
29-
- 'yarn.lock'
30-
- '.yarnrc.yml'
31-
- '*.base.json'
32-
- '*.base.js'
33-
- '.prettier*.*'
34-
- 'azure-pipelines-liikunta-review.yml'
35-
- 'Dockerfile'
36-
- '*.Dockerfile'
37-
- 'docker-compose.yml'
38-
- 'docker-compose.*.yml'
39-
- '!**/README.md'
26+
- 'apps/sports-helsinki/**'
27+
- 'packages/**'
28+
- 'package.json'
29+
- 'yarn.lock'
30+
- '.yarnrc.yml'
31+
- '*.base.json'
32+
- '*.base.js'
33+
- '.prettier*.*'
34+
- 'azure-pipelines-liikunta-review.yml'
35+
- 'Dockerfile'
36+
- '*.Dockerfile'
37+
- 'docker-compose.yml'
38+
- 'docker-compose.*.yml'
39+
- '!**/README.md'
4040

4141
# By default, use self-hosted agents
4242
pool: Default
4343

4444
resources:
4545
repositories:
46-
# Azure DevOps repository
47-
- repository: liikunta-pipelines
48-
type: git
49-
# Azure DevOps project/repository
50-
name: liikunta/liikunta-pipelines
46+
# Azure DevOps repository
47+
- repository: liikunta-pipelines
48+
type: git
49+
# Azure DevOps project/repository
50+
name: liikunta/liikunta-pipelines
5151

5252
extends:
5353
# Filename in Azure DevOps Repository (note possible -ui or -api)

0 commit comments

Comments
 (0)