英文:
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/29912318/fetching-a-url-from-the-init-func-in-go-on-appengine
英文:
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/29912318/fetching-a-url-from-the-init-func-in-go-on-appengine
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论