从Go中的init()函数在AppEngine上获取URL

huangapple go评论87阅读模式
英文:

Fetching a URL From the init() func in Go on AppEngine

问题

背景:我在GAE上运行Go,并使用Mux作为我的路由器。为了获取一个URL,GAE要求我使用其内置的urlFetch功能。我想在我的模块的init()函数中进行这个URL获取,但据我所知,只有在通过处理程序调用时才能使用urlFetch。

func init() {
  r := mux.NewRouter()
  r.HandleFunc("/", homeHandler)
  r.HandleFunc("/about", anotherHandler)
  http.Handle("/", r)
}

GAE建议使用以下代码进行urlFetch:

c := appengine.NewContext(r)
client := urlfetch.Client(c)

...但它的参数是一个http路由器,并且如果我传递我的mux路由器,它就无法工作。所以我不知道如何在URL处理程序的范围之外进行这个urlFetch。

当传递mux路由器时出现错误:"cannot use r (type *mux.Router) as type *http.Request in argument to "appengine".NewContext"

英文:

Background: I'm running Go on GAE and using Mux for my router. In order to fetch a URL GAE requires that I use its built in urlFetch capability. I want to make this URL fetch happen during my modules init() but as far as I can tell I can only use urlFetch when invoked via a handler.

func init() {
  r := mux.NewRouter()
  r.HandleFunc("/", homeHandler)
  r.HandleFunc("/about", anotherHandler)
  http.Handle("/", r)
}

GAE suggests the following code for making a urlFetch:

c := appengine.NewContext(r)
client := urlfetch.Client(c)

... but its argument is an http router, and it doesn't want to work if I pass my mux router. So I'm out of ideas of how to make this urlFetch happen outside the scope of a URL handler.

Error when passing the mux router: "cannot use r (type *mux.Router) as type *http.Request in argument to "appengine".NewContext"

答案1

得分: 4

你不能在处理程序之外使用需要Context的AppEngine服务(因为创建Context需要一个*http.Request值)。这意味着你也不能在包的init()函数中使用它们。

你需要重构你的代码,使得服务(在你的情况下是urlFetch)从处理程序中调用。

一个可能的解决方案是在为用户请求提供服务的处理程序中检查初始化是否完成。如果没有完成,执行你本来会放在init()中的初始化函数,然后再继续为请求提供服务。

是的,这可能会导致第一个请求的处理时间较长。为了避免这种情况,我建议你使用预热请求。预热请求是在新实例启动并开始为用户请求提供服务之前发送的。在你的app.yaml配置文件中,你可以通过在inbound_services指令中添加-warmup来启用预热请求:

inbound_services:
  - warmup

这将导致App Engine基础架构首先向/_ah/warmup发送一个GET请求。你可以注册一个处理程序来处理这个URL并执行初始化任务。和其他请求一样,在预热处理程序中你将有一个http.Request

但请注意:

> ..即使在你的应用中启用了预热请求,你仍然可能遇到加载请求

这意味着在极少数情况下,新实例可能不会收到预热请求,所以最好在用户处理程序中也检查初始化状态。

英文:

You can't use AppEngine services that require a Context outside of handlers (because the creation of a Context requires an *http.Request value). This by nature means you can't use them in package init() functions either.
<sub>Note that you can use them from cron jobs and tasks added to task queues, because tasks and cron jobs are executed by issuing HTTP GET requests.</sub>

You have to restructure your code so that the service (urlFetch in your case) gets called from a handler.

A possible solution is to check if init completed in handlers that serve user requests. If not, perform the initialization function you would otherwise put in init() before proceeding to serve the request.

Yes, this may cause first requests to take considerably longer to serve. For this purpose (to avoid this) I recommend you to utilize Warmup requests. A warmup request is issued to a new instance before it goes "live", before it starts serving user requests. In your app.yaml config file you can enable warmup requests by adding -warmup to the inbound_services directive:

inbound_services:
  - warmup

This will cause the App Engine infrastructure to first issue a GET request to /_ah/warmup. You can register a handler to this URL and perform initialization tasks. As with any other request, you will have an http.Request in the warmup handler.

But please note that:

> ..you may encounter loading requests, even if warmup requests are enabled in your app.

Which means that in rare cases it may happen a new instance will not receive a warmup request, so its best to check initialization state in user handlers too.

huangapple
  • 本文由 发表于 2015年4月28日 14:54:34
  • 转载请务必保留本文链接:https://go.coder-hub.com/29912318.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定