I am currently trying to work on a small Go project, and I have a problem I am trying to solve.
I'm currently using github.com/jinzhu/gorm to handle database operations for the backend of a GraphQL server, and I wanted to be able to store the DB connection in a global variable accessible throughout the entire project (including sub-packages).
My first attempt was at creating a variable named db by doing the following in my main.go file:
var db *gorm.DB
var err error
then inside the init() function:
func init() {
db, err = gorm.Open("postgres", "credential stuff here")
db.AutoMigrate(&modelStructHere)
defer db.Close()
}
There isn't any crashing, but I would assume due to scoping, the db variable is only usable inside main.go, but I also need to be able to use this inside gql/gql.go, where my GraphQL resolver is currently located.
Perhaps I should move this chunk of code (DB init) to the actual resolver file, since there's really no use for DB operations outside of such a thing anyway, so maybe that's the problem?
Thanks in advance!
Alex's comment is spot on. Create a folder named "database" and inside put a file called "database.go" containing this:
package database
// the imports go here
var DB *gorm.DB
Now you can use it wherever you like with database.DB. You should not make the error variable global, handle it in the same function that initializes the DB. The init function can be in any place, usually you want it at the beginning of your program in the main function.
Related
I want to run some Lambda alias specific code before my main function starts executing. It currently looks like this
func init() {
// Trying to get Lambda function alias here
}
func main() {
adapter = chiproxy.New(r)
lambda.start(lambdaHandler)
}
func lambdaHandler(ctx context.Context, req events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) {
c, err := adapter.ProxyWithContext(ctx, req)
return c, err
}
req in lambdaHandler has the info I need but I don't know how to get it in init()?
I don't think you can get the alias before the function has been passed a request. lambda automatically provides a number of environment variables but alias is not one of them.
That's probably because the alias is just a pointer to the version; you could have many aliases pointing to the same version, but the same function runtime could be initialized for all of them. So it wouldn't make sense to provide any particular alias at initialization time.
I want to run some Lambda alias specific code before my main function starts executing
But the function's runtime isn't specific to an alias, it's specific to a version. In fact you could create a new alias after the version had been instantiated, and the same cached runtime could be used.
I think I can see why you might want to have invokers call the same function with different aliases, but I'm not sure it's going to be a low friction path to achieve what you want with aliases. Consider whether you might instead want to create bunch of different functions - which could have the same codebase, and have init choose a proper handler or do other init based on the function name instead of its alias.
I am doing some web develoment using the go programming language using the package html/template. At some point of the code, I need to call the function template.ParseFiles(...) so I can create a template from those files ad then execute it using temp.Execute(w,data). I would like to know if it is better to create the template on each request or to do it once in the main and declare a global variable.
Right now I do it on each request on my handle functions, like most tutorials do. However, I don't know If I'm wasting resources by doing it on each request instead of having them as global variables.
This is how it looks on each request
func ViewStats(w http.ResponseWriter, r *http.Request) {
//Get stuff from db and put them in data
//...
//return data to user
tmp, err := template.ParseFiles("views/guest-layout.html",
"views/stats.html")
if err != nil {
fmt.Println(err)
} else {
tmp.Execute(w,data)
}
}
I would like to know if this is better:
var temp1 template.Template
func main() {
temp1, err = template.ParseFiles("file1","file2")
//...
}
As usual: It depends.
But first some nuance:
You should never do template parsing (or anything else interesting) in your main() function. Instead, your main() function should call methods (or a single method) that kicks off the chain of interesting things in your program.
Go doesn't have globals, so it's not actually an option to store your parsed templates in a global variable in the first place. The closest Go has to global variables is package variables. You could store your parsed templates in a package variable in the main package, but this is also bad form, as your main package (except for tiny, trivial programs), should just be an entry point, and otherwise nearly empty.
But now, on to the core of your question:
Should you parse templates per request, or per run?
And here it depends.
If you have templates that change frequently (i.e. during development, when you're constantly editing your HTML files), once per request can be best.
But this is far less efficient than just parsing once, so in production, you may wish to parse the templates once on startup only. Then you can store the templates in a package variable, or better, in a struct that is initialized at runtime. But I leave that to you.
But what may be best is actually a bit of a compromise between the two approaches. It may be best to load your templates at start-up, and re-load them occasionally, either automatically (say, every 5 minutes), or watch your filesystem, and reload them whenever the on-disk representation of the templates changes.
How to do this is left as an exercise for the reader.
I'm using gin gonic as an HTTP framework and I need to group some paths with shared variable by like this:
ur := r.Group("/")
ur.Use(package.Prepare)
{
ur.GET("/", package.Home)
}
Inside the Prepare handler, I declare package variable like
package.tplPath because I want all sub routes can access to this variable instead of rewrite the code in each http handler.
var tplPath = ""
func Prepare(c *gin.Context) {
_, filename, _, _ := runtime.Caller(0)
s := helper.RelativeFilePath(filename)
tplPath = s[1:len(s)] + "template/"
}
I don't know how Go works with each process, and variables for each http request. If a variable was declared in package level, will it be set after each http request?
Is this considered good practice? If not, why not?
This is not threadsafe, package variables are shared across all goroutines, and modification in one routine will change the value in all the others, causing a data race.
In general; try and avoid using package level variables where possible.
Edit:
In go, packages are a kind of module. There exists only one instance of a package for any given import path (basically package name). This means that there is only 1 instance of any variable at package level.
Package variables are shared, global state. All accessors of that variable will be accessing the exact same memory.
It does not matter what type the package variable is, struct / string / int etc. If it is defined at package level, all accessors of that variable will share the same instance of it.
If (as with http servers) you have concurrent code, there will be multiple accessors of that variable at the same time. In some situations this is fine, like when that variable is only ever read, but it appears that in your case it will be modified. Making this code racy!
The tplPath is a global variable, all routine will access the same memory address, and set after each http request.
If you want set just once, and the tplPath not depend on the http request. You can set it in the init function.
func init(){
_, filename, _, _ := runtime.Caller(0)
s := helper.RelativeFilePath(filename)
tplPath = s[1:len(s)] + "template/"
}
The init function will run before main, and just do once.
I have a GO project with this project structure (multiple couples of this kind of files in each package).
- api
- userHandler.go
- userHandler_test.go
- database
- user.go
- user_test.go
Inside user.go I have the User struct and the functions to Create/Get/Update a User (I'm using GORM but this is not the issue). In the user_test.go.
I'd like to have the DB cleaned (with all the data removed or in a certain state) for each different file, so I've tried to create 1 suite (using Testify) for each file, then use the SetupSuite function but the behaviour seems not deterministic, and probably I'm doing something wrong.
So my questions are:
Which is the best way to have a DB connection shared? Using a global variable is the best option?
Which is the best way to create the tables in the DB once and then init the DB with custom data before each file_test.go is run?
Right now I'm also having a strange bug: running
go test path/package1
go test path/package2
Everything works fine, but if I run (for testing all the packages)
cd path && go test ./...
I have errors that seems not to be deterministic, that's why I'm guessing that the DB connection is not handled properly
If your api package depends on your database package (which it appears to) then your api package should have a way to provide a database connection pool (e.g. a *sql.DB) to it.
In your tests for the api package, you should just pass in an initialised pool (perhaps with the test schema/fixtures pre-populated) that you can use. This can either be a global you initialise in init() for the api package or a setup() and defer teardown() pattern in each test function.
Here's the former (simplest) approach where you just create a shared database and schema for your tests to use.
package database
import testing
var testDB *sql.DB
// This gets run before your actual test functions do.
func init() {
var err error
db, err = sql.Open(...)
if err != nil {
log.Fatalf("test init failed: %s", err)
}
_, err := db.Exec(`CREATE TABLE ....`)
if err != nil {
log.Fatalf("test schema creation failed: %s", err)
}
}
Some tips:
You can also call a setup() function can create a table with a random suffix and insert your test data so that your tests don't use the same test table (and therefore risk conflicting or relying on each other). Capture that table name and dump it in your defer teardown() function.
https://medium.com/#benbjohnson/structuring-applications-in-go-3b04be4ff091 is worth reading for some additional perspective.
I'm trying to build a very simple Go web application, and the golang "a folder per package" structure is making things difficult for me.
I'm using github.com/gorilla/mux as the router and github.com/unrolled/render for template rendering. This means that I need to create a new router and a new renderer when the app launches, and I need all my routes to access the renderer.
This is super easy to do in a single file:
func main() {
...
r := render.New(render.Options{
// a lot of app specific setup
})
mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
r.HTML(w, http.StatusOK, "myTemplate", nil)
})
...
}
However, this is where I don't understand Go. Because I want the routes in separate files in a subfolder (my project will grow), that forces them to be in a routes package. Of course that makes the renderer variable inaccesssible. I can't just create the renderer in the routes package, because the render.New() call relies on a me passing in a ton of app specific stuff like the template folder, and helpers for asset paths.
I went down the route of making my handler functions work on a struct with an already initialized renderer...
func (app *App) Hello2(w http.ResponseWriter, r *http.Request) {
app.Renderer.HTML(w, http.StatusOK, "myTemplate", nil)
}
But I'm still confused as to how I'm going to access this app *App in the routes package when it's initialized in main. Everything in Go seems super easy if you have a flat list of files, but as soon as you want a bit of folder structure, the package setup becomes problematic.
There's probably something I'm missing here, so any help is appreciated.
Here's general info on dealing with dependencies in Go. A key trick is, you just have to declare the Render variable in a package that your views can import. You could create a myapp/render package with a var Render that's either inited in the package itself (func init()) or set from main.
But the context thing you found sounds totally sane, though it might be more than this app needs. The neat thing about it is that because the context is set in per-request code, later you could extend it to do sneaky things like use the Host: header to provide a different Layout for people loading the app via different domains. If the Layout is baked into a global, you can't. This can be a real advantage--I've tried to retrofit per-request changes onto big codebases whose config was sprayed around various global variables, and it's a pain.