1
0
Fork 0
toolkit/packages/cache/src/internal/uploadUtils.ts

167 lines
4.3 KiB
TypeScript
Raw Normal View History

2024-06-13 10:16:59 +00:00
import * as core from '@actions/core'
import {
2024-09-24 10:17:44 +00:00
BlobClient,
2024-11-24 18:44:39 +00:00
BlobUploadCommonResponse,
2024-09-24 10:17:44 +00:00
BlockBlobClient,
2024-06-13 10:16:59 +00:00
BlockBlobParallelUploadOptions
} from '@azure/storage-blob'
2024-12-02 10:33:27 +00:00
import {TransferProgressEvent} from '@azure/ms-rest-js'
2024-11-28 11:53:34 +00:00
import {InvalidResponseError} from './shared/errors'
import {UploadOptions} from '../options'
2024-06-13 10:16:59 +00:00
2024-12-02 10:33:27 +00:00
/**
* Class for tracking the upload state and displaying stats.
*/
export class UploadProgress {
contentLength: number
sentBytes: number
startTime: number
displayedComplete: boolean
timeoutHandle?: ReturnType<typeof setTimeout>
constructor(contentLength: number) {
this.contentLength = contentLength
this.sentBytes = 0
this.displayedComplete = false
this.startTime = Date.now()
}
/**
* Sets the number of bytes sent
*
* @param sentBytes the number of bytes sent
*/
setSentBytes(sentBytes: number): void {
this.sentBytes = sentBytes
}
/**
* Returns the total number of bytes transferred.
*/
getTransferredBytes(): number {
return this.sentBytes
}
/**
* Returns true if the upload is complete.
*/
isDone(): boolean {
return this.getTransferredBytes() === this.contentLength
}
/**
* Prints the current upload stats. Once the upload completes, this will print one
* last line and then stop.
*/
display(): void {
if (this.displayedComplete) {
return
}
const transferredBytes = this.sentBytes
const percentage = (100 * (transferredBytes / this.contentLength)).toFixed(
1
)
const elapsedTime = Date.now() - this.startTime
const uploadSpeed = (
transferredBytes /
(1024 * 1024) /
(elapsedTime / 1000)
).toFixed(1)
core.info(
`Sent ${transferredBytes} of ${this.contentLength} (${percentage}%), ${uploadSpeed} MBs/sec`
)
if (this.isDone()) {
this.displayedComplete = true
}
}
/**
* Returns a function used to handle TransferProgressEvents.
*/
onProgress(): (progress: TransferProgressEvent) => void {
return (progress: TransferProgressEvent) => {
this.setSentBytes(progress.loadedBytes)
}
}
/**
* Starts the timer that displays the stats.
*
* @param delayInMs the delay between each write
*/
startDisplayTimer(delayInMs = 1000): void {
const displayCallback = (): void => {
this.display()
if (!this.isDone()) {
this.timeoutHandle = setTimeout(displayCallback, delayInMs)
}
}
this.timeoutHandle = setTimeout(displayCallback, delayInMs)
}
/**
* Stops the timer that displays the stats. As this typically indicates the upload
* is complete, this will display one last line, unless the last line has already
* been written.
*/
stopDisplayTimer(): void {
if (this.timeoutHandle) {
clearTimeout(this.timeoutHandle)
this.timeoutHandle = undefined
}
this.display()
}
}
2024-11-28 11:53:34 +00:00
export async function uploadCacheArchiveSDK(
signedUploadURL: string,
archivePath: string,
options?: UploadOptions
2024-11-28 11:53:34 +00:00
): Promise<BlobUploadCommonResponse> {
2024-12-02 10:33:27 +00:00
const blobClient: BlobClient = new BlobClient(signedUploadURL)
const blockBlobClient: BlockBlobClient = blobClient.getBlockBlobClient()
const properties = await blobClient.getProperties()
const contentLength = properties.contentLength ?? -1
const uploadProgress = new UploadProgress(contentLength)
2024-06-13 10:16:59 +00:00
// Specify data transfer options
const uploadOptions: BlockBlobParallelUploadOptions = {
blockSize: options?.uploadChunkSize,
concurrency: options?.uploadConcurrency, // maximum number of parallel transfer workers
2024-12-02 10:33:27 +00:00
maxSingleShotSize: 128 * 1024 * 1024, // 128 MiB initial transfer size
onProgress: uploadProgress.onProgress()
2024-11-14 11:22:03 +00:00
}
2024-06-13 10:16:59 +00:00
2024-12-02 11:08:05 +00:00
// try {
uploadProgress.startDisplayTimer()
2024-06-13 10:16:59 +00:00
2024-12-02 11:08:05 +00:00
core.debug(
`BlobClient: ${blobClient.name}:${blobClient.accountName}:${blobClient.containerName}`
)
2024-12-02 11:08:05 +00:00
const response = await blockBlobClient.uploadFile(archivePath, uploadOptions)
2024-12-02 10:33:27 +00:00
2024-12-02 11:08:05 +00:00
// TODO: better management of non-retryable errors
if (response._response.status >= 400) {
throw new InvalidResponseError(
`Upload failed with status code ${response._response.status}`
)
2024-12-02 10:33:27 +00:00
}
2024-12-02 11:08:05 +00:00
return response
// } catch (error) {
// core.debug(`Error uploading cache archive: ${error}`)
// throw error
// } finally {
// uploadProgress.stopDisplayTimer()
// }
2024-11-14 11:22:03 +00:00
}