1
- import * as cliProgress from 'cli-progress' ;
2
- import { asyncify , mapLimit } from 'async' ;
3
- import { Manifest , ManifestFile } from './manifest' ;
4
1
import _colors = require( 'colors' ) ;
5
-
6
- import { Storage } from '@google-cloud/storage' ;
2
+ import { asyncify , mapLimit } from 'async' ;
7
3
import { Datastore } from '@google-cloud/datastore' ;
8
4
import { entity } from '@google-cloud/datastore/build/src/entity' ;
5
+ import { Manifest , ManifestFile } from './manifest' ;
6
+ import { Storage } from '@google-cloud/storage' ;
7
+ import * as cliProgress from 'cli-progress' ;
9
8
10
9
const datastore = new Datastore ( ) ;
11
-
12
10
const DEFAULT_BUCKET = `${ process . env . GCLOUD_PROJECT } .appspot.com` ;
13
-
14
11
const NUM_CONCURRENT_UPLOADS = 64 ;
15
12
16
13
function getBlobPath ( siteId : string , hash : string ) {
@@ -68,62 +65,67 @@ export async function uploadManifest(
68
65
const filesToUpload = force
69
66
? manifest . files
70
67
: await findUploadedFiles ( manifest , storageBucket ) ;
71
- const numFiles = filesToUpload . length ;
68
+ const numTotalFiles = filesToUpload . length ;
72
69
console . log (
73
70
`Found new ${ filesToUpload . length } files out of ${ manifest . files . length } total...`
74
71
) ;
75
72
76
- if ( numFiles > 0 ) {
77
- let totalTransferred = 0 ;
78
- let numProcessed = 0 ;
73
+ if ( numTotalFiles <= 0 ) {
74
+ finalize ( manifest , ttl ) ;
75
+ } else {
76
+ let bytesTransferred = 0 ;
77
+ let numProcessedFiles = 0 ;
79
78
const startTime = Math . floor ( Date . now ( ) / 1000 ) ;
80
- bar . start ( numFiles , numProcessed , {
79
+ bar . start ( numTotalFiles , numProcessedFiles , {
81
80
speed : 0 ,
82
81
} ) ;
82
+ // @ts -ignore
83
+ bar . on ( 'stop' , ( ) => {
84
+ finalize ( manifest , ttl ) ;
85
+ } ) ;
83
86
84
87
mapLimit (
85
88
filesToUpload ,
86
89
NUM_CONCURRENT_UPLOADS ,
87
90
asyncify ( async ( manifestFile : ManifestFile ) => {
88
- const remotePath = getBlobPath ( manifest . site , manifestFile . hash ) ;
89
-
90
- // NOTE: This was causing stale responses, even when rewritten by the client-server: 'public, max-age=31536000',
91
+ // NOTE: After testing, it seems we need a public Cache-Control with a
92
+ // minimum max age of ~3600 seconds (1 hour) for the "high performance"
93
+ // mode to kick in. Our best guess is that when this Cache-Control
94
+ // setting is used, responses are cached internally within GCP yielding
95
+ // much higher performance. That said, we don't want end users to
96
+ // receive potentially stale content, so the proxy response rewrites
97
+ // this header to 36 seconds (from 3600).
98
+ // The following docs indicate that Cache-Control doesn't apply for
99
+ // private blobs, however we've observed differences in performance per
100
+ // the above.
91
101
// https://cloud.google.com/storage/docs/gsutil/addlhelp/WorkingWithObjectMetadata#cache-control
92
- // NOTE: In order for GCS to respond extremely fast, it requires a longer cache expiry time.
93
- // TODO: See if we can remove this from the proxy response without killing perf.
94
102
const metadata = {
95
103
cacheControl : 'public, max-age=3600' ,
96
104
contentType : manifestFile . mimetype ,
97
105
metadata : {
98
106
path : manifestFile . cleanPath ,
99
107
} ,
100
108
} ;
101
-
102
109
// TODO: Veryify this correctly handles errors and retry attempts.
110
+ const remotePath = getBlobPath ( manifest . site , manifestFile . hash ) ;
103
111
const resp = await storageBucket . upload ( manifestFile . path , {
104
112
// NOTE: `gzip: true` must *not* be set here. Doing so interferes
105
113
// with the proxied GCS response. Despite not setting `gzip: true`,
106
114
// the response remains gzipped from the proxy server.
107
115
destination : remotePath ,
108
116
metadata : metadata ,
109
117
} ) ;
110
- totalTransferred += parseInt ( resp [ 1 ] . size ) ;
118
+ bytesTransferred += parseInt ( resp [ 1 ] . size ) ;
111
119
const elapsed = Math . floor ( Date . now ( ) / 1000 ) - startTime ;
112
- bar . update ( ( numProcessed += 1 ) , {
113
- speed : ( totalTransferred / elapsed / ( 1024 * 1024 ) ) . toFixed ( 2 ) ,
120
+ const speed = ( bytesTransferred / elapsed / ( 1024 * 1024 ) ) . toFixed ( 2 ) ;
121
+ bar . update ( ( numProcessedFiles += 1 ) , {
122
+ speed : speed ,
114
123
} ) ;
115
- if ( numProcessed === numFiles ) {
124
+ if ( numProcessedFiles === numTotalFiles ) {
116
125
bar . stop ( ) ;
117
126
}
118
127
} )
119
128
) ;
120
-
121
- // @ts -ignore
122
- bar . on ( 'stop' , ( ) => {
123
- finalize ( manifest , ttl ) ;
124
- } ) ;
125
- } else {
126
- finalize ( manifest , ttl ) ;
127
129
}
128
130
}
129
131
@@ -140,7 +142,7 @@ async function finalize(manifest: Manifest, ttl?: Date) {
140
142
const manifestPaths = manifest . toJSON ( ) ;
141
143
const now = new Date ( ) ;
142
144
143
- // Create shortSha mapping for staging .
145
+ // Create shortSha mapping, so a shortSha can be used to lookup filesets .
144
146
const key = datastore . key ( [
145
147
'Fileset2Manifest' ,
146
148
`${ manifest . site } :ref:${ manifest . shortSha } ` ,
@@ -152,7 +154,8 @@ async function finalize(manifest: Manifest, ttl?: Date) {
152
154
paths : manifestPaths ,
153
155
} ) ;
154
156
155
- // Create branch mapping for staging.
157
+ // Create branch mapping, so a branch name can be used to lookup filesets.
158
+ // TODO: Use clean branch name to avoid non-URL-safe branch names.
156
159
if ( manifest . branch ) {
157
160
const branchKey = datastore . key ( [
158
161
'Fileset2Manifest' ,
@@ -172,10 +175,10 @@ async function finalize(manifest: Manifest, ttl?: Date) {
172
175
// const routerKey = datastore.key(['Fileset2Router', manifest.site]);
173
176
// const router = await datastore.get(routerKey);
174
177
// const entity = router && router[0];
175
-
176
178
console . log (
177
179
`Finalized upload for site: ${ manifest . site } -> ${ manifest . branch } @ ${ manifest . shortSha } `
178
180
) ;
181
+ // TODO: Allow customizing the staging URL using `fileset.yaml` configuration.
179
182
console . log (
180
183
`Staged: https://${ manifest . site } -${ manifest . shortSha } -dot-fileset2-dot-${ process . env . GCLOUD_PROJECT } .appspot.com`
181
184
) ;
0 commit comments