Apex Process exited before completing request when with Golang - mysql

All the answers for something like this are in Javascript, and I'm not sure if it applies in Go.
I've done this
func main() {
db, err := sql.Open("mysql", "db_details")
err = db.Ping()
if err != nil {
fmt.Println("Failed to prepare connection to database")
// log.Fatal("Error:", err.Error())
}
apex.HandleFunc(func(event json.RawMessage, ctx *apex.Context) (interface{}, error) {
fmt.Println(ctx)
return map[string]string{"hello": "world"}, nil
})
}
So I'm trying to hit my Amazon RDS MySql db using golang's sql driver.
I get this error
Error: function response: Response Id: <some_id> Process exited before completing request
From looking around, there are two causes - 1. I need Go's equivalent of context.done, or 2. I need to raise the timeout.
As I'm using Apex, I raised the timeout to be 300s, which is the maximum. No luck there.
I then tried going through the Apex code to see if there was a Context.Done defined or used anywhere - there isn't.
How do I get around this?

Related

simple planetscale - golang app won't select the database properly

After connecting to a Planetscale database using DSN with the following structure:
user:password#tcp(host)/database?tls=true
I decided to test it by running a simple query. Here's my main.go file:
package main
import (
"database/sql"
"fmt"
"os"
_ "github.com/go-sql-driver/mysql"
)
func GetDatabase() (*sql.DB, error) {
db, err := sql.Open("mysql", os.Getenv("DSN"))
return db, err
}
func main() {
db, err := GetDatabase()
if err != nil {
panic(err)
}
if err := db.Ping(); err != nil {
panic(err)
}
// ---
query, err := db.Query("SELECT name FROM status;")
if err != nil {
panic(err.Error())
}
var name string
for query.Next() {
err = query.Scan(&name)
if err != nil {
panic(err.Error())
}
fmt.Println(name)
}
// ---
fmt.Println("Successfully connected to PlanetScale!")
}
If I remove the section between the two comment lines, it will print out the 'successfully connected' message; however, if I try to run it including the query part, the outcome changes to:
panic: Error 1046: No database selected
Well, I decided to try with the query:
"USE database; SELECT name FROM status;"
However, the default driver won't take multiple statements and returns syntax error.
I know it seems like a simple question, but I already read the documentation from planetscale, from the go mysql driver, and I haven't been able to overcome this little issue. Any help will be greatly appreciated.
Looks like the problem is with the .env file. If I save the same information to a string variable within the same GetDatabase() function, and then pass it as argument instead of os.Getenv(), it connects normally. Can't tell exactly why that happens, but if someone can provide further information, I'll be thankful.
Edit:
when saving my credentials to an .env file, and using the built-in function os.Getenv("DSN"), the program will indeed connect to planetscale, but it won't select the given database in the DSN string. As mentioned in the question, selecting the database first and then running statements / queries doesn't work because of the constraints of the driver.
If I hard code the variables to a string variable, eg:
dsn := "root:mlc#tcp(127.0.0.1:3306)/app"
and then use that to open the connection, this time the program will use the desired database with any problem.

How does one discern the error number of a MySQL execution in Go?

stmt, err := db.Prepare("SQL Stuff")
if err != nil {
log.Fatal(err)
}
res, err := stmt.Exec(add a variable)
if err != nil {
log.Fatal(err)
}
This is how I am currently handling my MySQL based errors in Go.
As it stands when I run into trouble with my SQL command or something else an error comes through, hits the 'if' and properly prints the error to the console ending the program.
I know when I see the console reading there are error numbers like these : https://dev.mysql.com/doc/refman/5.5/en/error-messages-server.html .
So I would assume that the thrown error itself has the number inside of it. I'd like to respond to situations like "The row is present" or "Not a unique value" because in some situations I have responses for them.
Is there a succinct method to discerning what the error number is?
It depends on which MySQL driver you're using. If it is github.com/go-sql-driver/mysql, then it does expose the error number in the MySQLError type. You could do something like this:
if merr, ok := err.(*mysql.MySQLError); ok {
// This is an error from MySQL. Use merr.Number as the error number
} else {
// This error isn't necessarily from MySQL. Usual error processing
}

Golang http request POST works once

I have a master and slave. Master have api call result, which takes JSON. And i have proplem with slave, which send this result on master, the first time my code sends json well, but second time, code stop(program wait.....) on resp, err := client.Do(req), when create query on master.
salve code:
func main (){
for {
// some code, very long code
sendResult(resFiles)
}
}
func sendResult(rf common.ResultFiles) {
jsonValue, err := json.Marshal(rf)
req, err := http.NewRequest(methodPost, ResultAdress,
bytes.NewBuffer(jsonValue))
req.Header.Set("Content-Type", ContentType)
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
fmt.Println("response Status:", resp.Status)
}
master api call:
func result(c echo.Context) error {
rf := &ResultFiles{}
err := c.Bind(rf)
if err != nil {
log.Fatal(err)
}
rfChannel <- *rf
return c.JSON(http.StatusOK, nil)
}
My question: Why? May be problem in the standard client golang (http.Client) or timeout? If i set timout - my code crashed by timeout)))anticipated....
Thank you!
You need to add a timeout to your http.Client. By default http.Client has timeout specified as 0 which means no timeout at all. So if server is not responding than your application will just hang waiting for a response. This problem is fully described in this article Don’t use Go’s default HTTP client (in production). Though you create custom client you still need to specify timeout.
Problem link with channel, i send result work slave on master to channel, but channel work without loop, i add loop for read data from channel and all work.

Why does sql.Open() return nil as error when it should not?

I am trying to connect to a mysql database.
I tried to see if I would get an error if I gave it wrong connection information but it still returns nil as error. Even If I shut down mysql completely it still does not return an error. What is the point of check for errors after this function if it does not return errors?
This is on Windows, I am using XAMPP and I don't have a password for the database. Username is "root".
import (
"database/sql"
"log"
_ "github.com/go-sql-driver/mysql"
)
func main() {
db, err := sql.Open("mysql", "root#tcp(127.0.0.1:3306)/dbname?charset=utf8")
if err != nil {
log.Fatal(err)
}
defer db.Close()
}
SQL.Open only creates the DB object, but does not open any connections to the database. If you want to test your connections you have to execute a query to force opening a connection. The common way for this is to call Ping() on your DB object.
See http://golang.org/pkg/database/sql/#Open and http://golang.org/pkg/database/sql/#DB.Ping
Quoting from the doc of sql.Open():
Open may just validate its arguments without creating a connection to the database. To verify that the data source name is valid, call Ping.
As stated, Open() may not open any physical connection to the database server, but it will validate its arguments. That being said if arguments are valid, it may return nil error even if the database server is not reachable, or even if the host denoted by dataSourceName does not exist.
To answer your other question:
What is the point of check for errors after this function if it does not return errors?
You have to check returned errors because it can return errors. For example if the specified driverName is invalid, a non-nil error will be returned (see below).
To test if the database server is reachable, use DB.Ping(). But you can only use this if the returned error is nil, else the returned DB might also be nil (and thus calling the Ping() method on it may result in run-time panic):
if db, err := sql.Open("nonexistingdriver", "somesource"); err != nil {
fmt.Println("Error creating DB:", err)
fmt.Println("To verify, db is:", db)
} else {
err = db.Ping()
if err != nil {
fmt.Println("db.Ping failed:", err)
}
}
Output (try it on the Go Playground):
Error creating DB: sql: unknown driver "nonexistingdriver" (forgotten import?)
To verify, db is: <nil>
It turns out that this does not actually connect to the database right away.
Source: http://go-database-sql.org/accessing.html
To check the validity of connection, we can do this:
db, err := sql.Open("mysql", "root#tcp(127.0.0.1:3306)/dbname?charset=utf8")
err = db.Ping() // Need to do this to check that the connection is valid
if err != nil {
log.Fatal(err)
}

Catching panics in Golang

With the following code, if no file argument is given, a panic is thrown for line 9 panic: runtime error: index out of range as expected.
How can I 'catch' this panic and handle it when directly when passing something to it (os.Args[1]) that causes the panic? Much like try/catch in PHP or try/except in Python.
I've had a search here on StackOverflow but I've not found anything that answers this as such.
package main
import (
"fmt"
"os"
)
func main() {
file, err := os.Open(os.Args[1])
if err != nil {
fmt.Println("Could not open file")
}
fmt.Printf("%s", file)
}
A panicking program can recover with the builtin recover() function:
The recover function allows a program to manage behavior of a panicking goroutine. Suppose a function G defers a function D that calls recover and a panic occurs in a function on the same goroutine in which G is executing. When the running of deferred functions reaches D, the return value of D's call to recover will be the value passed to the call of panic. If D returns normally, without starting a new panic, the panicking sequence stops. In that case, the state of functions called between G and the call to panic is discarded, and normal execution resumes. Any functions deferred by G before D are then run and G's execution terminates by returning to its caller.
The return value of recover is nil if any of the following conditions holds:
panic's argument was nil;
the goroutine is not panicking;
recover was not called directly by a deferred function.
Here is an example of how to use this:
// access buf[i] and return an error if that fails.
func PanicExample(buf []int, i int) (x int, err error) {
defer func() {
// recover from panic if one occured. Set err to nil otherwise.
if (recover() != nil) {
err = errors.New("array index out of bounds")
}
}()
x = buf[i]
}
Notice that more often than not, panicking is not the right solution. The Go paradigm is to check for errors explicitly. A program should only panic if the circumstances under which it panics do not happen during ordinary program executing. For instance, not being able to open a file is something that can happen and should not cause a panic while running out of memory is worth a panic. Nevertheless, this mechanism exists to be able to catch even these cases and perhaps shut down gracefully.
Go is not python, you should properly check for args before you use it:
func main() {
if len(os.Args) != 2 {
fmt.Printf("usage: %s [filename]\n", os.Args[0])
os.Exit(1)
}
file, err := os.Open(os.Args[1])
if err != nil {
log.Fatal(err)
}
fmt.Printf("%s", file)
}
Some Golang official packages use panic/defer+recover as throw/catch, but only when they need to unwind a large call stack. In Golang's json package using panic/defer+recover as throw/catch is the most elegant solution.
from http://blog.golang.org/defer-panic-and-recover
For a real-world example of panic and recover, see the json package from the Go standard library. It decodes JSON-encoded data with a set of recursive functions. When malformed JSON is encountered, the parser calls panic to unwind the stack to the top-level function call, which recovers from the panic and returns an appropriate error value (see the 'error' and 'unmarshal' methods of the decodeState type in decode.go).
Search for d.error(
at http://golang.org/src/encoding/json/decode.go
In your example the "idiomatic" solution is to check the parameters before using them, as other solutions have pointed.
But, if you want/need to catch anything you can do:
package main
import (
"fmt"
"os"
)
func main() {
defer func() { //catch or finally
if err := recover(); err != nil { //catch
fmt.Fprintf(os.Stderr, "Exception: %v\n", err)
os.Exit(1)
}
}()
file, err := os.Open(os.Args[1])
if err != nil {
fmt.Println("Could not open file")
}
fmt.Printf("%s", file)
}
First: You wouldn't want to do this. Try-catch-style error handling is no error handling. In Go you would check len(os.Args) first and access element 1 only if present.
For the rare cases you need to catch panics (and your case is not one of them!) use defer in combination with recover. See http://golang.org/doc/effective_go.html#recover
We can manage panic without halting process using recover. By calling recover in any function using defer it will return the execution to calling function. Recover returns two values one is boolean and other one is interface to recover. Using type assertion we can get underlying error value
You can also print underlying error using recover.
defer func() {
if r := recover(); r != nil {
var ok bool
err, ok = r.(error)
if !ok {
err = fmt.Errorf("pkg: %v", r)
}
}
}()
I had to catch panics in a test case. I got redirected here.
func.go
var errUnexpectedClose = errors.New("Unexpected Close")
func closeTransaction(a bool) {
if a == true {
panic(errUnexpectedClose)
}
}
func_test.go
func TestExpectedPanic() {
got := panicValue(func() { closeTransaction(true) })
a, ok := got.(error)
if a != errUnexpectedClose || !ok {
t.Error("Expected ", errUnexpectedClose.Error())
}
}
func panicValue(fn func()) (recovered interface{}) {
defer func() {
recovered = recover()
}()
fn()
return
}
Used from https://github.com/golang/go/commit/e4f1d9cf2e948eb0f0bb91d7c253ab61dfff3a59 (ref from VonC)
Note that the recover treatment of a panic Execution error (such as attempting to index an array out of bounds trigger) might change with go 1.7 after issue 14965
See CL 21214 and its test:
runtime: make execution error panic values implement the Error interface
Make execution panics implement Error as mandated by Run-time panics (specs), instead of panics with strings.
When you recover a panic error, you would be able to do:
if _, ok := recovered.(runtime.Error); !ok {
This is still being evaluated, and as Dave Cheney. mentions:
I don't know what people are currently doing but from my POV this has been broken for a long time and nobody has complained so they are either explicitly relying on the broken behaviour, or nobody cares. Either way I think it's a good idea to avoid making this change.