初始化 Go AppEngine 应用程序与 Cloud Datastore。

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

Initializing Go AppEngine app with Cloud Datastore

问题

在GAE的golang应用程序的init()函数中,我该如何设置应用程序的初始值?

在init()函数中或应用程序启动后立即如何从Cloud Datastore中读取数据?据我了解,服务器无法写入本地文件系统,Cloud Datastore是唯一的选择?

我需要一些全局变量和数据切片。

英文:

in init() function for GAE's golang app, how can I set-up initial values for my application ?

How to read from Cloud Datastore in the init() function or immediately after applications start-up ? As I understand, server cannot write to the local filesystem and Cloud Datastore is the only option ?

I need some global variables and slices of data..

答案1

得分: 2

使用静态文件

在AppEngine上,您无法访问主机操作系统的文件系统,但可以访问您的Web应用程序的文件(您只有只读权限,无法更改它们,也无法在应用程序文件夹中创建新文件)。

所以问题是:您的应用程序代码是否可以更改要读取和用于初始化的数据?或者将其与应用程序代码一起“静态”部署是否可以?

如果您不需要更改它(或仅在重新部署应用程序时需要更改),最简单的方法是将其存储为Web应用程序的“静态”文件的一部分。您可以使用相对路径引用应用程序的文件,其中当前或工作目录是应用程序的根目录。例如,如果您的应用程序在其根目录(app.yaml所在的位置)中包含一个data文件夹,并且data文件夹中有一个init_values.txt文件,则可以使用路径data/init_values.txt引用它。

一个重要的注意事项:并非每个文件都可以被代码读取,这取决于应用程序的配置。引用自使用app.yaml配置/静态文件处理程序

> 如果您有需要应用程序代码读取的数据文件,那么数据文件必须是应用程序文件,并且不能与静态文件模式匹配。

使用Datastore

您无法在处理程序之外使用需要Context的AppEngine服务(因为创建Context需要一个*http.Request值)。这意味着您也无法在包的init()函数中使用它们。
<sub>请注意,您可以从cron作业和添加到任务队列的任务中使用它们,因为任务和cron作业是通过发出HTTP GET请求来执行的。</sub>

您必须重构代码,使您的初始化(例如从Datastore读取)从处理程序中调用。

使用Once.Do()实现的示例:

var once = sync.Once{}

func MainHandler(w http.ResponseWriter, r *http.Request) {
    ctx := appengine.NewContext(r)
    once.Do(func() { mysetup(ctx) })
    // 在这里执行常规操作
}

func mysetup(ctx appengine.Context) {
    // 此函数仅执行一次。
    // 从Datastore中读取并初始化变量。
}

“利用”预热请求

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

inbound_services:
  - warmup

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

但请注意:

> ..即使在应用中启用了预热请求,您可能会遇到加载请求

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


相关问题:

https://stackoverflow.com/questions/34629056/how-do-i-store-the-private-key-of-my-server-in-google-app-engine

https://stackoverflow.com/questions/29912318/fetching-a-url-from-the-init-func-in-go-on-appengine

https://stackoverflow.com/questions/33336850/environment-variables-specified-on-app-yaml-but-its-not-fetching-on-main-go

英文:

Using static files

On AppEngine you don't have access to the file system of the host operating system, but you can access files of your web application (you have read-only permission, you can't change them and you can't create new files in the app's folder).

So the question is: can your application's code change the data that you want to read and use for initialization? Or is it fine if it is deployed "statically" with your app's code?

If you don't need to change it (or only when you redeploy your app), easiest is to store it as a "static" file as part of your webapp. You may refer to files of your app using relative paths, where the current or working directory is your app's root. E.g. if your app contains a data folder in its root (where app.yaml resides), and there is an init_values.txt file inside the data folder, you can refer to it with the path: data/init_values.txt.

One important note: not every file is readable by code, this depends on the app configuration. Quoting from Configuring with app.yaml / Static file handlers:

> If you have data files that need to be read by the application code, the data files must be application files, and must not be matched by a static file pattern.

Using the Datastore

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 your initialization (e.g. reading from the Datastore) gets called from a handler.

Example of achieving this with Once.Do():

var once = sync.Once{}

func MainHandler(w http.ResponseWriter, r *http.Request) {
	ctx := appengine.NewContext(r)
	once.Do(func() { mysetup(ctx) })
	// do your regular stuff here
}

func mysetup(ctx appengine.Context) {
	// This function is executed only once.
	// Read from Datastore and initialize your vars here.
}

"Utilizing" warmup requests

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.


Related questions:

https://stackoverflow.com/questions/34629056/how-do-i-store-the-private-key-of-my-server-in-google-app-engine

https://stackoverflow.com/questions/29912318/fetching-a-url-from-the-init-func-in-go-on-appengine

https://stackoverflow.com/questions/33336850/environment-variables-specified-on-app-yaml-but-its-not-fetching-on-main-go

huangapple
  • 本文由 发表于 2016年3月24日 01:19:40
  • 转载请务必保留本文链接:https://go.coder-hub.com/36184701.html
匿名

发表评论

匿名网友

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

确定