Skip to content
This repository was archived by the owner on Jun 16, 2024. It is now read-only.

Commit 275b3cf

Browse files
committed
simpler /api/conference cache by cloudfront invalidation
1 parent d84211a commit 275b3cf

13 files changed

+49
-45
lines changed

Gemfile

+1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ gem 'aws-sdk-chimesdkidentity'
1515
gem 'aws-sdk-chimesdkmessaging'
1616
gem 'aws-sdk-ivs'
1717
gem 'aws-sdk-medialive'
18+
gem 'aws-sdk-cloudfront'
1819

1920
gem 'shoryuken'
2021
gem 'aws-sdk-sqs'

Gemfile.lock

+4
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,9 @@ GEM
7474
aws-sdk-chimesdkmessaging (1.18.0)
7575
aws-sdk-core (~> 3, >= 3.165.0)
7676
aws-sigv4 (~> 1.1)
77+
aws-sdk-cloudfront (1.76.0)
78+
aws-sdk-core (~> 3, >= 3.165.0)
79+
aws-sigv4 (~> 1.1)
7780
aws-sdk-core (3.171.0)
7881
aws-eventstream (~> 1, >= 1.0.2)
7982
aws-partitions (~> 1, >= 1.651.0)
@@ -239,6 +242,7 @@ PLATFORMS
239242
DEPENDENCIES
240243
aws-sdk-chimesdkidentity
241244
aws-sdk-chimesdkmessaging
245+
aws-sdk-cloudfront
242246
aws-sdk-core
243247
aws-sdk-ivs
244248
aws-sdk-medialive

app/controllers/api/conferences_controller.rb

+2-5
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,9 @@ class Api::ConferencesController < Api::ApplicationController
33

44
def show
55
now = Time.zone.now
6-
lifetime = 15.seconds
7-
grace = 2.minutes
8-
response.date = now
9-
response.headers['expires'] = (now+lifetime).httpdate
6+
7+
expires_in 5.seconds, public: true, 's-maxage' => 300
108
(response.cache_control[:extras] ||= []) << 'no-cache="Set-Cookie"'
11-
response.cache_control.merge!( public: true, stale_while_revalidate: grace, stale_if_error: grace )
129

1310
render(json: {
1411
requested_at: now.to_i,

app/javascript/ScreenAnnounceView.tsx

+1-8
Original file line numberDiff line numberDiff line change
@@ -23,14 +23,7 @@ import { GitHubIcon } from "./GitHubIcon";
2323
import { TwitterIcon } from "./TwitterIcon";
2424

2525
export const ScreenAnnounceView: React.FC = () => {
26-
const { data, mutate } = Api.useConference();
27-
28-
// XXX: i know i can use useSWR refreshInterval
29-
//React.useEffect(() => {
30-
// const interval = setInterval(() => mutate(), 1000);
31-
// return () => clearInterval(interval);
32-
//}, []);
33-
26+
const { data } = Api.useConference();
3427
const card = data?.conference?.tracks?._screen?.card;
3528

3629
const fillerElem = (

app/javascript/SubScreen.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ export const SubScreen: React.FC = () => {
3737
type InfoMode = "announcement" | "lightning_timer" | "caption";
3838

3939
export const SubScreenInner: React.FC<{ trackSlug: TrackSlug }> = ({ trackSlug }) => {
40-
const { data: conferenceData, error: conferenceError, mutate: mutateConferenceData } = Api.useConference();
40+
const { data: conferenceData } = Api.useConference();
4141
const chat = useChat();
4242
const systemsChannel = chat.systems_channel_arn;
4343

app/javascript/TrackPage.tsx

+1-27
Original file line numberDiff line numberDiff line change
@@ -29,33 +29,7 @@ export const TrackPageInner: React.FC = () => {
2929
const { slug: trackSlug } = useParams();
3030
if (!trackSlug) throw new Error("?"); // XXX:
3131

32-
const { data: conferenceData, error: conferenceError, mutate: mutateConferenceData } = Api.useConference();
33-
34-
React.useEffect(() => {
35-
if (!conferenceData) return;
36-
if (conferenceData.requested_at === 0) return; // Partially mutated by consumeIvsMetadata
37-
38-
const now = dayjs();
39-
const isStale = conferenceData.stale_after && conferenceData.stale_after - 2 <= now.unix();
40-
console.log("conferenceData freshness", {
41-
isStale,
42-
now: now.toISOString(),
43-
at: dayjs.unix(conferenceData.requested_at).toISOString(),
44-
stale_after: dayjs.unix(conferenceData.stale_after).toISOString(),
45-
});
46-
47-
if (isStale) {
48-
console.log("conferenceData is stale; request revalidation");
49-
mutateConferenceData();
50-
const interval = setInterval(() => {
51-
console.log("Revalidating stale conferenceData...");
52-
mutateConferenceData();
53-
}, 1000);
54-
return () => clearInterval(interval);
55-
} else {
56-
console.log("conferenceData is fresh!");
57-
}
58-
}, [conferenceData?.requested_at, conferenceData?.stale_after]);
32+
const { data: conferenceData, error: conferenceError } = Api.useConference();
5933

6034
if (!conferenceData) {
6135
return (

app/jobs/emit_conference_data_job.rb

+2
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ def perform(t: Time.zone.now, route:)
2020
body: JSON.generate(body),
2121
)
2222

23+
PurgeCloudfrontCacheJob.perform_later(['/api/conference'])
24+
2325
case route
2426
when :both
2527
send_ivs(outpost_key)
+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
class PurgeCloudfrontCacheJob < ApplicationJob
2+
def perform(paths)
3+
distribution_id = Rails.configuration.x.cdn.cloudfront_distribution_id
4+
return unless distribution_id
5+
6+
@cloudfront = Aws::CloudFront::Client.new(region: 'us-east-1', logger: Rails.logger)
7+
@cloudfront.create_invalidation(
8+
distribution_id: distribution_id,
9+
invalidation_batch: {
10+
paths: {
11+
quantity: paths.size,
12+
items: paths
13+
},
14+
caller_reference: "#{self.class.name}-#{Rails.env}-#{job_id}"
15+
},
16+
)
17+
end
18+
end

config/environments/development.rb

+6-3
Original file line numberDiff line numberDiff line change
@@ -14,16 +14,19 @@
1414
config.x.s3.public_prefix = ENV['TAKEOUT_S3_PREFIX'] || 'dev/'
1515
config.x.s3.public_region = ENV['TAKEOUT_S3_REGION'] || 'ap-northeast-1'
1616
config.x.sentry.dsn = ENV['SENTRY_DSN']
17-
config.x.release_meta.commit = ''
18-
config.x.release_meta.version = ''
19-
config.x.release_meta.cache_buster = ENV['TAKEOUT_CACHE_BUSTER']
17+
18+
config.x.cdn.cloudfront_distribution_id = ENV['TAKEOUT_CLOUDFRONT_DISTRIBUTION_ID']
2019

2120
config.x.control.password = ENV['TAKEOUT_CONTROL_PASSWORD']
2221
config.x.kiosk.password = ENV['TAKEOUT_KIOSK_PASSWORD']
2322

2423
config.x.oidc.signing_key = ENV['OIDC_SIGNING_KEY']&.yield_self { |der| OpenSSL::PKey::RSA.new(der.unpack1('m*'), '') } \
2524
|| (Rails.root.join('tmp', 'oidc.key').read rescue nil)&.yield_self { |pem| OpenSSL::PKey::RSA.new(pem, '') }
2625

26+
config.x.release_meta.commit = ''
27+
config.x.release_meta.version = ''
28+
config.x.release_meta.cache_buster = ENV['TAKEOUT_CACHE_BUSTER']
29+
2730
config.active_job.queue_adapter = ENV.fetch('ENABLE_SHORYUKEN', '1') == '1' ? :inline : :shoryuken
2831

2932
# In the development environment your application's code is reloaded any time

config/environments/production.rb

+2
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
config.x.s3.public_prefix = ENV.fetch('TAKEOUT_S3_PREFIX')
1919
config.x.s3.public_region = ENV.fetch('TAKEOUT_S3_REGION')
2020

21+
config.x.cdn.cloudfront_distribution_id = ENV['TAKEOUT_CLOUDFRONT_DISTRIBUTION_ID']
22+
2123
config.x.control.password = ENV.fetch('TAKEOUT_CONTROL_PASSWORD')
2224
config.x.kiosk.password = ENV.fetch('TAKEOUT_KIOSK_PASSWORD')
2325

deploy/hako/base.libsonnet

+2
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ local secret = utils.makeSecretParameterStore('takeout-app');
3838

3939
TAKEOUT_STAFF_ONLY: '1',
4040
TAKEOUT_STAFF_ONLY_STREAM: '0',
41+
42+
TAKEOUT_CLOUDFRONT_DISTRIBUTION_ID: 'E3G1QIEKS0IAW',
4143
},
4244
secrets: [
4345
secret('DATABASE_URL'),

tf/cloudfront.tf

+1-1
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ resource "aws_cloudfront_distribution" "takeout-rk-o" {
126126

127127
min_ttl = 0
128128
default_ttl = 0
129-
max_ttl = 60
129+
max_ttl = 3600
130130

131131
compress = true
132132
viewer_protocol_policy = "redirect-to-https"

tf/iam_heroku-takeout-prd.tf

+8
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,14 @@ data "aws_iam_policy_document" "takeout-prd" {
105105
]
106106
}
107107

108+
statement {
109+
effect = "Allow"
110+
actions = [
111+
"cloudfront:GetInvalidation",
112+
"cloudfront:CreateInvalidation",
113+
]
114+
resources = [aws_cloudfront_distribution.takeout-rk-o.arn]
115+
}
108116
}
109117

110118
resource "aws_iam_policy" "heroku-takeout-prd" {

0 commit comments

Comments
 (0)