33// license that can be found in the LICENSE file. 
44
55/* 
6- Package delay provides a way to execute code outside the scope of a 
7- user request by using the taskqueue API. 
8- 
9- To declare a function that may be executed later, call Func 
10- in a top-level assignment context, passing it an arbitrary string key 
11- and a function whose first argument is of type context.Context. 
12- The key is used to look up the function so it can be called later. 
13- 	var laterFunc = delay.Func("key", myFunc) 
14- It is also possible to use a function literal. 
15- 	var laterFunc = delay.Func("key", func(c context.Context, x string) { 
16- 		// ... 
17- 	}) 
18- 
19- To call a function, invoke its Call method. 
20- 	laterFunc.Call(c, "something") 
21- A function may be called any number of times. If the function has any 
22- return arguments, and the last one is of type error, the function may 
23- return a non-nil error to signal that the function should be retried. 
24- 
25- The arguments to functions may be of any type that is encodable by the gob 
26- package. If an argument is of interface type, it is the client's responsibility 
27- to register with the gob package whatever concrete type may be passed for that 
28- argument; see http://golang.org/pkg/gob/#Register for details. 
29- 
30- Any errors during initialization or execution of a function will be 
31- logged to the application logs. Error logs that occur during initialization will 
32- be associated with the request that invoked the Call method. 
33- 
34- The state of a function invocation that has not yet successfully 
35- executed is preserved by combining the file name in which it is declared 
36- with the string key that was passed to the Func function. Updating an app 
37- with pending function invocations should safe as long as the relevant 
38- functions have the (filename, key) combination preserved. The filename is 
39- parsed according to these rules: 
40-   * Paths in package main are shortened to just the file name (github.com/foo/foo.go -> foo.go) 
41-   * Paths are stripped to just package paths (/go/src/github.com/foo/bar.go -> github.com/foo/bar.go) 
42-   * Module versions are stripped (/go/pkg/mod/github.com/foo/[email protected] /baz.go -> github.com/foo/bar/baz.go) 43- 
44- There is some inherent risk of pending function invocations being lost during 
45- an update that contains large changes. For example, switching from using GOPATH 
46- to go.mod is a large change that may inadvertently cause file paths to change. 
47- 
48- The delay package uses the Task Queue API to create tasks that call the 
49- reserved application path "/_ah/queue/go/delay". 
50- This path must not be marked as "login: required" in app.yaml; 
51- it must be marked as "login: admin" or have no access restriction. 
6+ Package delay provides a way to execute code outside of the scope of 
7+ a user request by using the Task Queue API. 
8+ To use a deferred function, you must register the function to be 
9+ deferred as a top-level var. For example, 
10+     ``` 
11+     var laterFunc = delay.MustRegister("key", myFunc) 
12+     func myFunc(ctx context.Context, a, b string) {...} 
13+     ``` 
14+ You can also inline with a function literal: 
15+     ``` 
16+     var laterFunc = delay.MustRegister("key", func(ctx context.Context, a, b string) {...}) 
17+     ``` 
18+ In the above example, "key" is a logical name for the function. 
19+ The key needs to be globally unique across your entire application. 
20+ To invoke the function in a deferred fashion, call the top-level item: 
21+     ``` 
22+     laterFunc(ctx, "aaa", "bbb") 
23+     ``` 
24+ This will queue a task and return quickly; the function will be actually 
25+ run in a new request. The delay package uses the Task Queue API to create 
26+ tasks that call the reserved application path "/_ah/queue/go/delay". 
27+ This path may only be marked as "login: admin" or have no access 
28+ restriction; it will fail if marked as "login: required". 
5229*/ 
5330package  delay // import "google.golang.org/appengine/v2/delay" 
5431
@@ -151,34 +128,72 @@ func fileKey(file string) (string, error) {
151128	return  modVersionPat .ReplaceAllString (file , "" ), nil 
152129}
153130
154- // Func declares a new Function. The second argument must be a function with a 
155- // first argument of type context.Context. 
156- // This function must be called at program initialization time. That means it 
157- // must be called in a global variable declaration or from an init function. 
158- // This restriction is necessary because the instance that delays a function 
159- // call may not be the one that executes it. Only the code executed at program 
160- // initialization time is guaranteed to have been run by an instance before it 
161- // receives a request. 
131+ // Func declares a new function that can be called in a deferred fashion. 
132+ // The second argument i must be a function with the first argument of 
133+ // type context.Context. 
134+ // To make the key globally unique, the SDK code will combine "key" with 
135+ // the filename of the file in which myFunc is defined 
136+ // (e.g., /some/path/myfile.go). This is convenient, but can lead to 
137+ // failed deferred tasks if you refactor your code, or change from 
138+ // GOPATH to go.mod, and then re-deploy with in-flight deferred tasks. 
139+ // 
140+ // This function Func must be called in a global scope to properly 
141+ // register the function with the framework. 
142+ // 
143+ // Deprecated: Use MustRegister instead. 
162144func  Func (key  string , i  interface {}) * Function  {
163- 	f  :=  & Function {fv : reflect .ValueOf (i )}
164- 
165145	// Derive unique, somewhat stable key for this func. 
166146	_ , file , _ , _  :=  runtime .Caller (1 )
167147	fk , err  :=  fileKey (file )
168148	if  err  !=  nil  {
169149		// Not fatal, but log the error 
170150		stdlog .Printf ("delay: %v" , err )
171151	}
172- 	f .key  =  fk  +  ":"  +  key 
152+ 	key  =  fk  +  ":"  +  key 
153+ 	f , err  :=  registerFunction (key , i )
154+ 	if  err  !=  nil  {
155+ 		return  f 
156+ 	}
157+ 	if  old  :=  funcs [f .key ]; old  !=  nil  {
158+ 		old .err  =  fmt .Errorf ("multiple functions registered for %s" , key )
159+ 	}
160+ 	funcs [f .key ] =  f 
161+ 	return  f 
162+ }
163+ 
164+ // MustRegister declares a new function that can be called in a deferred fashion. 
165+ // The second argument i must be a function with the first argument of 
166+ // type context.Context. 
167+ // MustRegister requires the key to be globally unique. 
168+ // 
169+ // This function MustRegister must be called in a global scope to properly 
170+ // register the function with the framework. 
171+ // See the package notes above for more details. 
172+ func  MustRegister (key  string , i  interface {}) * Function  {
173+ 	f , err  :=  registerFunction (key , i )
174+ 	if  err  !=  nil  {
175+ 		panic (err )
176+ 	}
177+ 
178+ 	if  old  :=  funcs [f .key ]; old  !=  nil  {
179+ 		panic (fmt .Errorf ("multiple functions registered for %q" , key ))
180+ 	}
181+ 	funcs [f .key ] =  f 
182+ 	return  f 
183+ }
184+ 
185+ func  registerFunction (key  string , i  interface {}) (* Function , error ) {
186+ 	f  :=  & Function {fv : reflect .ValueOf (i )}
187+ 	f .key  =  key 
173188
174189	t  :=  f .fv .Type ()
175190	if  t .Kind () !=  reflect .Func  {
176191		f .err  =  errors .New ("not a function" )
177- 		return  f 
192+ 		return  f ,  f . err 
178193	}
179194	if  t .NumIn () ==  0  ||  ! isContext (t .In (0 )) {
180195		f .err  =  errFirstArg 
181- 		return  f 
196+ 		return  f ,  errFirstArg 
182197	}
183198
184199	// Register the function's arguments with the gob package. 
@@ -194,12 +209,7 @@ func Func(key string, i interface{}) *Function {
194209		}
195210		gob .Register (reflect .Zero (t .In (i )).Interface ())
196211	}
197- 
198- 	if  old  :=  funcs [f .key ]; old  !=  nil  {
199- 		old .err  =  fmt .Errorf ("multiple functions registered for %s in %s" , key , file )
200- 	}
201- 	funcs [f .key ] =  f 
202- 	return  f 
212+ 	return  f , nil 
203213}
204214
205215type  invocation  struct  {
0 commit comments