| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| throw new FirebaseError("Functions did not deploy properly."); | ||
| } | ||
| // Once everything has been added to queues, starting processing. | ||
| // Note: We need to set up these wait before calling process and close. |
There was a problem hiding this comment.
Figuring this out drove me up a wall for a day and a half :(. It turns out that our implementation of throttler.wait() returns a promise that never resolves if you call it after .process() and .close(). I'd like to fix this at some point, but that code is used in a bunch of other places that I don't understand well enough to test effectively.
Sorry, something went wrong.
| export interface RegionalDeployment { | ||
| region: string; | ||
| sourceToken?: string; | ||
| firstFunctionDeployment?: () => any; |
There was a problem hiding this comment.
Realized that I could turn this into an implementation detail of runRegionalFunctionDeployment, so I removed this from the type.
Sorry, something went wrong.
| import Queue from "./throttler/queue"; | ||
|
|
||
| // TODO: Get rid of this when switching to use operation-poller. | ||
| // TODO(joehan): Get rid of this once we refactor functions-delete.js |
There was a problem hiding this comment.
This file has a mix of random helper functions, and chaff from the old deployment code that I can't quite delete yet because its used on functions-delete and other code paths. I'm gonna make another PR later to clean up the old functions, and move the still relevant functions into a less generically named file inside of the src/deploy/functions directory.
Sorry, something went wrong.
| export async function checkHttpIam(context: any, options: any, payload: any): Promise<void> { | ||
| const functionsInfo = payload.functions.triggers; | ||
| const filterGroups = getFilterGroups(options); | ||
| const filterGroups = context.filters; |
There was a problem hiding this comment.
The implementation for getFilterGroups() looks very different from what you've done here. Could you share a bit more insight into why this change was necessary?
(Also - if this change is intended, we could get rid of the import statement on getFilterGroups)
Sorry, something went wrong.
There was a problem hiding this comment.
Good catch on the import! Its not the prettiest code flow, but in prepare.ts, we have a line that already does this work: context.filters = getFilterGroups().
I figured it would be nice to avoid redoing this work - however, it does sacrifice some readability, and it could lead to subtle bugs if this code ever gets used elsewhere. I'll make this fall back to getFilterGroups() if context.filters is undefined.
Sorry, something went wrong.
| projectId: projectId, | ||
| region: helper.getRegion(name), | ||
| functionName, | ||
| functionName: name, |
There was a problem hiding this comment.
I keep getting confused what name refers to in different context.
Say we are given functions resource projects/my-projc/locations/us-central1/functions/myfunc. In this case, name has to bee the fully-qualified name (with project Id & location) right?
If that's right, I'm starting to get worried that this could become a source of pain and bugs. Is that your experience as well?
Sorry, something went wrong.
There was a problem hiding this comment.
The Google API style guide defines myfunc as the "id" and projects/my-projc/locations/us-central1/functions/myfunc as the "name". IMO the only solution here is to be pedantically consistent.
Sorry, something went wrong.
There was a problem hiding this comment.
This definitely is confusing and ive introduced a few bugs during development because of it. I'll go through and switch everything to id and name to follow the style guide
Sorry, something went wrong.
| ); | ||
| const operationResult = await pollOperation<void>(pollerOptions); | ||
| params.timer.endTimer(fnName); | ||
| helper.printSuccess(fnName, "delete"); |
There was a problem hiding this comment.
If I'm reading this correctly, I think this will print fully qualified name (including project, region) vs other tasks print function name only. Is that okay?
Sorry, something went wrong.
There was a problem hiding this comment.
This is working as intended - printSuccess takes a fully qualified name. CloudFunctionTrigger.name is the fully qualified name, so the other tasks behave the same way.
Sorry, something went wrong.
| const defaultPollerOptions = { | ||
| apiOrigin: functionsOrigin, | ||
| apiVersion: cloudfunctions.API_VERSION, | ||
| masterTimeout: 150000, |
There was a problem hiding this comment.
nit* can we write this as
40 * 60 * 60 // 40 hours
Also - did I get this right? 40 hours looks like a very generous timeout.
Sorry, something went wrong.
There was a problem hiding this comment.
If we're guessing what the units are in this timeout that's a good hint that it should be included in the variable name. E.g. masterTimeoutMs
Sorry, something went wrong.
There was a problem hiding this comment.
This is in ms, so its 150 seconds. I'll add a comment clarifying this for now. I'd like to make some improvements to throttler at some point in the future since it wasn't the clearest to work with here - when I do so, I'll rename this option to masterTimeoutMs for clarity.
Sorry, something went wrong.
There was a problem hiding this comment.
LGTM with the logging fixes Daniel pointed out.
Sorry, something went wrong.
| import * as logger from "../../logger"; | ||
| import { FirebaseError } from "../../error"; | ||
|
|
||
| type OperationType = |
There was a problem hiding this comment.
enum string types make my heart sing. Thanks for this.
Sorry, something went wrong.
| for (const failedDep of failedIamCalls) { | ||
| logger.info(`\t${failedDep.functionName}`); | ||
| } | ||
| logger.info("\nUnauthorized users will not be able access this function."); |
There was a problem hiding this comment.
I think you mean unauthenticated. One never wants an unauthorized user to have access.
Sorry, something went wrong.
There was a problem hiding this comment.
You are correct! I'm also gonna get @egilmorez to take a look at this to shop the language further at some point.
Sorry, something went wrong.
| } | ||
| logger.info("\nUnauthorized users will not be able access this function."); | ||
| logger.info( | ||
| "\nThis may be caused by an organization policy that restricts Network Access on your project." |
There was a problem hiding this comment.
Or because roles/functions.developer doesn't have functions.setIamPermission on it. You need to be a roles/functions.admin. The required permissions is a major oversight in my opinion, but this is a battle we've already lost.
Sorry, something went wrong.
There was a problem hiding this comment.
Ooof, I didn't realize that was the case. I'll reword this to have a bulleted list of common reasons, and include that as the first one.
Sorry, something went wrong.
| logger.info("\nTo continue deploying other features (such as database), run:"); | ||
| logger.info(" " + clc.bold("firebase deploy --except functions")); | ||
| // Print all the original messages at debug level. | ||
| for (const failedDep of this.errors) { |
There was a problem hiding this comment.
what does "Dep" mean? I read "dependency" in my head, but it's nothing that starts with "dep" in the struct.
Sorry, something went wrong.
There was a problem hiding this comment.
Deployment - I'll replace this with the full word to make this clearer
Sorry, something went wrong.
| import * as clc from "cli-color"; | ||
|
|
||
| import * as ensureApiEnabled from "../../ensureApiEnabled"; | ||
| import { ensure, check } from "../../ensureApiEnabled"; |
There was a problem hiding this comment.
FWIW, I actually preferred the namespaced option since "ensure" and "check" are so generic. Up to you though.
Sorry, something went wrong.
| const defaultPollerOptions = { | ||
| apiOrigin: functionsOrigin, | ||
| apiVersion: cloudfunctions.API_VERSION, | ||
| masterTimeout: 150000, |
There was a problem hiding this comment.
If we're guessing what the units are in this timeout that's a good hint that it should be included in the variable name. E.g. masterTimeoutMs
Sorry, something went wrong.
| "..." | ||
| ); | ||
| params.timer.startTimer(fn.name, "create"); | ||
| const eventType = fn.eventTrigger ? fn.eventTrigger.eventType : "https"; |
There was a problem hiding this comment.
Just to make sure I understand the latest JS, could this have been written fn?.eventTrigger?.eventType || "https"
Sorry, something went wrong.
There was a problem hiding this comment.
Yep, it could have been written either way
Sorry, something went wrong.
| export function createFunctionTask( | ||
| params: TaskParams, | ||
| fn: CloudFunctionTrigger, | ||
| onPoll?: (op: any) => any |
There was a problem hiding this comment.
This is any synchronous callback to be invoked when a polling operation happens? Surely we can at least type the argument to the function. And I'm assuming the return type is void?
Sorry, something went wrong.
There was a problem hiding this comment.
Ahh yes, this was an oversight - will fix
Sorry, something went wrong.
| region: helper.getRegion(fn.name), | ||
| eventType: eventType, | ||
| functionName: helper.getFunctionName(fn.name), | ||
| functionName: helper.getFunctionId(fn.name), |
There was a problem hiding this comment.
Not for this PR for we should change functionName argument to functionId soon? I volunteer to do that later.
Sorry, something went wrong.
There was a problem hiding this comment.
Ahhh, this one slipped past me. I like the idea of doing this in a separate PR later - it should be easier to track down any places we missed it then
Sorry, something went wrong.
| const scheduleName = helper.getScheduleName(name, appEngineLocation); | ||
| const topicName = helper.getTopicName(name); | ||
| const functionName = helper.getFunctionName(name); | ||
| const functionName = helper.getFunctionId(name); |
There was a problem hiding this comment.
Same here - functionName vs Id is getting tricky.
Sorry, something went wrong.
There was a problem hiding this comment.
+100 on these - i just found another bug caused by this. I was accidentally using name instead of ID for a call to setIamPolicy, and didn't notice until now because that call was failing for me anyway due to the org policy.
Sorry, something went wrong.
| Back | FazBrowse Home | New Git URL |
Description
Refactors release.ts to build and execute deploymentPlans when deploying functions.
This also changes the release code to use the same operation polling and throttler code as the rest of the codebase. In a follow up PR, I'll get rid of the last few usages of the old polling code (in the functions:delete command), and I'll clean up that code as well.
Scenarios Tested
I've been running a ton of test deploys with this code and I'm going to continue to do so while this PR is under review. Some situations I've tested so far: