英文:
Why does golang concurrent uploading of files to S3 bucket result in canceled, context deadline exceeded
问题
我已经写了一小段用于递归遍历目录并上传目录中文件的 Golang 代码。目录中大约有93K+个项目。一段时间后,我遇到了以下错误:
上传文件时出错:/Users/randolphhill/Fat-Tree-Business/SandBox/DDD/heydoc/ios/Pods/gRPC-Core/src/core/ext/transport/chttp2/alpn/alpn.h
操作错误 S3: PutObject,https 响应错误 StatusCode: 0,RequestID: ,HostID: ,已取消,上下文截止时间已过。
以下是代码片段:
func PutFile(c context.Context, api S3PutObjectAPI, input *s3.PutObjectInput) (*s3.PutObjectOutput, error) {
return api.PutObject(c, input)
}
func PutFileS3(dir, filename, bucket, reg string) error {
var cfg aws.Config
st, err := fthash.Filehash(dir + filename)
if err != nil {
panic("configuration error, " + err.Error())
return err
}
m := make(map[string]string)
m["hashcode"] = st
cfg, err = config.LoadDefaultConfig(context.TODO(), config.WithRegion(reg))
if err != nil {
panic("configuration error, " + err.Error())
}
client := s3.NewFromConfig(cfg)
tmp := "backup" + dir + filename
uri := strings.Replace(tmp, " ", "##,##", -1)
if checkFileOnS3(client, bucket, uri, st) {
fmt.Println(" FILE EXIST")
return nil
}
file, err2 := os.Open(dir + filename)
defer file.Close()
if err2 != nil {
fmt.Println("Unable to open file " + filename)
return err2
}
tmp = "backup" + dir + filename
//uri := "backup" + dir + filename
uri = strings.Replace(tmp, " ", "##,##", -1)
input := &s3.PutObjectInput{
Bucket: &bucket,
Key: aws.String(uri),
Body: file,
Metadata: m,
}
ctx, cancelFn := context.WithTimeout(context.TODO(), 10*time.Second)
defer cancelFn()
_, err2 = PutFile(ctx, client, input)
if err2 != nil {
fmt.Println("Got error uploading file:", dir+filename)
fmt.Println(err2)
return err2
}
return nil
}
希望对你有帮助!
英文:
I have written a small golang piece of code to recursive traverse a directory and upload the files in the director. There are approximately 93K+ items in the directory.
After a while I get the following error:
Got error uploading file: /Users/randolphhill/Fat-Tree-Business/SandBox/DDD/heydoc/ios/Pods/gRPC-Core/src/core/ext/transport/chttp2/alpn/alpn.h
operation error S3: PutObject, https response error StatusCode: 0, RequestID: , HostID: , canceled, context deadline exceeded.
Below is the code snippet
func PutFile(c context.Context, api S3PutObjectAPI, input *s3.PutObjectInput) (*s3.PutObjectOutput, error) {
return api.PutObject(c, input)
}
func PutFileS3(dir, filename, bucket, reg string) error {
var cfg aws.Config
st, err := fthash.Filehash(dir + filename)
if err != nil {
panic("configuration error, " + err.Error())
return err
}
m := make(map[string]string)
m["hashcode"] = st
cfg, err = config.LoadDefaultConfig(context.TODO(), config.WithRegion(reg))
if err != nil {
panic("configuration error, " + err.Error())
}
client := s3.NewFromConfig(cfg)
tmp := "backup" + dir + filename
uri := strings.Replace(tmp, " ", "##,##", -1)
if checkFileOnS3(client, bucket, uri, st) {
fmt.Println(" FILE EXIST")
return nil
}
file, err2 := os.Open(dir + filename)
defer file.Close()
if err2 != nil {
fmt.Println("Unable to open file " + filename)
return err2
}
tmp = "backup" + dir + filename
//uri := "backup" + dir + filename
uri = strings.Replace(tmp, " ", "##,##", -1)
input := &s3.PutObjectInput{
Bucket: &bucket,
Key: aws.String(uri),
//Key: &filename,
Body: file,
Metadata: m,
}
ctx, cancelFn := context.WithTimeout(context.TODO(), 10*time.Second)
defer cancelFn()
_, err2 = PutFile(ctx, client, input)
if err2 != nil {
fmt.Println("Got error uploading file:", dir+filename)
fmt.Println(err2)
return err2
}
return nil
}
答案1
得分: 1
你在这里添加了一个10秒的超时:
ctx, cancelFn := context.WithTimeout(context.TODO(), 10*time.Second)
defer cancelFn()
_, err2 = PutFile(ctx, client, input)
if err2 != nil {
fmt.Println("Got error uploading file:", dir+filename)
fmt.Println(err2)
return err2
}
10秒后,调用PutFile
将以上下文错误退出。如果你有需要更长时间上传的文件,你可能只需要增加超时时间。
英文:
You've added a 10 second timeout here:
ctx, cancelFn := context.WithTimeout(context.TODO(), 10*time.Second)
defer cancelFn()
_, err2 = PutFile(ctx, client, input)
if err2 != nil {
fmt.Println("Got error uploading file:", dir+filename)
fmt.Println(err2)
return err2
}
After 10 seconds, the call to PutFile
will exit with a context error. You likely just need to increase the timeout if you have files that take longer to upload.
答案2
得分: 0
package main
import (
// "html/template"
"log"
"net/http"
"os"
"github.com/gin-gonic/gin"
"github.com/joho/godotenv"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/credentials"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/s3/s3manager"
)
var AccessKeyID string
var SecretAccessKey string
var MyRegion string
var MyBucket string
var filepath string
//GetEnvWithKey : get env value
func GetEnvWithKey(key string) string {
return os.Getenv(key)
}
func LoadEnv() {
err := godotenv.Load(".env")
if err != nil {
log.Fatalf("Error loading .env file")
os.Exit(1)
}
}
func ConnectAws() *session.Session {
AccessKeyID = GetEnvWithKey("AWS_ACCESS_KEY_ID")
SecretAccessKey = GetEnvWithKey("AWS_SECRET_ACCESS_KEY")
MyRegion = GetEnvWithKey("AWS_REGION")
sess, err := session.NewSession(
&aws.Config{
Region: aws.String(MyRegion),
Credentials: credentials.NewStaticCredentials(
AccessKeyID,
SecretAccessKey,
"", // a token will be created when the session it's used.
),
})
if err != nil {
panic(err)
}
return sess
}
func SetupRouter(sess *session.Session) {
router := gin.Default()
router.Use(func(c *gin.Context) {
c.Set("sess", sess)
c.Next()
})
// router.Get("/upload", Form)
router.POST("/upload", UploadImage)
// router.GET("/image", controllers.DisplayImage)
_ = router.Run(":4000")
}
func UploadImage(c *gin.Context) {
sess := c.MustGet("sess").(*session.Session)
uploader := s3manager.NewUploader(sess)
MyBucket = GetEnvWithKey("BUCKET_NAME")
file, header, err := c.Request.FormFile("photo")
filename := header.Filename
//upload to the s3 bucket
up, err := uploader.Upload(&s3manager.UploadInput{
Bucket: aws.String(MyBucket),
//ACL: aws.String("public-read"),
Key: aws.String(filename),
Body: file,
})
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{
"error": "Failed to upload file",
"uploader": up,
})
return
}
filepath = "https://" + MyBucket + "." + "s3-" + MyRegion + ".amazonaws.com/" + filename
c.JSON(http.StatusOK, gin.H{
"filepath": filepath,
})
}
func main() {
LoadEnv()
sess := ConnectAws()
router := gin.Default()
router.Use(func(c *gin.Context) {
c.Set("sess", sess)
c.Next()
})
router.POST("/upload", UploadImage)
//router.LoadHTMLGlob("templates/*")
//router.GET("/image", func(c *gin.Context) {
//c.HTML(http.StatusOK, "index.tmpl", gin.H{
// "title": "Main website",
//})
//})
_ = router.Run(":4000")
}
英文:
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-html -->
package main
import (
// "html/template"
"log"
"net/http"
"os"
"github.com/gin-gonic/gin"
"github.com/joho/godotenv"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/credentials"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/s3/s3manager"
)
var AccessKeyID string
var SecretAccessKey string
var MyRegion string
var MyBucket string
var filepath string
//GetEnvWithKey : get env value
func GetEnvWithKey(key string) string {
return os.Getenv(key)
}
func LoadEnv() {
err := godotenv.Load(".env")
if err != nil {
log.Fatalf("Error loading .env file")
os.Exit(1)
}
}
func ConnectAws() *session.Session {
AccessKeyID = GetEnvWithKey("AWS_ACCESS_KEY_ID")
SecretAccessKey = GetEnvWithKey("AWS_SECRET_ACCESS_KEY")
MyRegion = GetEnvWithKey("AWS_REGION")
sess, err := session.NewSession(
&aws.Config{
Region: aws.String(MyRegion),
Credentials: credentials.NewStaticCredentials(
AccessKeyID,
SecretAccessKey,
"", // a token will be created when the session it's used.
),
})
if err != nil {
panic(err)
}
return sess
}
func SetupRouter(sess *session.Session) {
router := gin.Default()
router.Use(func(c *gin.Context) {
c.Set("sess", sess)
c.Next()
})
// router.Get("/upload", Form)
router.POST("/upload", UploadImage)
// router.GET("/image", controllers.DisplayImage)
_ = router.Run(":4000")
}
func UploadImage(c *gin.Context) {
sess := c.MustGet("sess").(*session.Session)
uploader := s3manager.NewUploader(sess)
MyBucket = GetEnvWithKey("BUCKET_NAME")
file, header, err := c.Request.FormFile("photo")
filename := header.Filename
//upload to the s3 bucket
up, err := uploader.Upload(&s3manager.UploadInput{
Bucket: aws.String(MyBucket),
//ACL: aws.String("public-read"),
Key: aws.String(filename),
Body: file,
})
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{
"error": "Failed to upload file",
"uploader": up,
})
return
}
filepath = "https://" + MyBucket + "." + "s3-" + MyRegion + ".amazonaws.com/" + filename
c.JSON(http.StatusOK, gin.H{
"filepath": filepath,
})
}
func main() {
LoadEnv()
sess := ConnectAws()
router := gin.Default()
router.Use(func(c *gin.Context) {
c.Set("sess", sess)
c.Next()
})
router.POST("/upload", UploadImage)
//router.LoadHTMLGlob("templates/*")
//router.GET("/image", func(c *gin.Context) {
//c.HTML(http.StatusOK, "index.tmpl", gin.H{
// "title": "Main website",
//})
//})
_ = router.Run(":4000")
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论