Getting More than 1 push notification using go lang cron

349 Views Asked by At

I am creating GO rest APIs. We are using AWS server. I want to send push notification to mobile. Then I used

https://pkg.go.dev/github.com/robfig/cron (https://github.com/robfig/cron )

for creating cron job.

We are using 2 version of API, V1(old one) and V1.1(new one)

we have more than 1 environment dev,QA,preproduction,production

in our go lang code I created a cron job for sending push notification to mobile. and the function called inside main().

But we are getting 2 notification each interval.

I didn't understand why 2 one is getting at a time

I am attaching my code.

const title = "This Week’s Activity"

func NotifyWeeklyActivity(db *sql.DB, logger *zap.Logger) {
    logger.Info("NotifyWeeklyActivity- start")
    c := cron.New()
    c.AddFunc("*/5 * * * *", func() {
        lastweekTime := CurrentUTC().AddDate(0, 0, -7)

        type PostCount struct {
            HiveID               uint64      `json:"hive_id"`
            Post                 uint64      `json:"post"`
            NotificationTopicArn null.String `json:"notification_topic_arn"`
        }
        var posts []PostCount
        err := queries.Raw(`
            select count(post_id) as post , post.hive_id as hive_id , hive.notification_topic_arn
            from post
            join hive on post.hive_id=hive.hive_id and hive.deleted_at is null
            where post.deleted_at is null
            and hive.deleted_at is null
            and post.created_at between ? and ?
            group by hive_id
            having count(post_id)>3 ;
    `, lastweekTime, CurrentUTC()).Bind(context.TODO(), db, &posts)

        if err != nil {
            logger.Error("error while fetching data ", zap.Error(err))
            // return err
        }
        cfg, _ := config.GetImpart()
        if cfg.Env != config.Local {
            notification := NewImpartNotificationService(db, string(cfg.Env), cfg.Region, cfg.IOSNotificationARN, logger)
            logger.Info("Notification- fetching complted")
            for _, hive := range posts {
                pushNotification := Alert{
                    Title: aws.String(title),
                    Body: aws.String(
                        fmt.Sprintf("Check out %d new posts in your Hive this week", hive.Post),
                    ),
                }
                additionalData := NotificationData{
                    EventDatetime: CurrentUTC(),
                    HiveID:        hive.HiveID,
                }
                Logger.Info("Notification",
                    zap.Any("pushNotification", pushNotification),
                    zap.Any("additionalData", additionalData),
                    zap.Any("hive", hive),
                )
                err = notification.NotifyTopic(context.Background(), additionalData, pushNotification, hive.NotificationTopicArn.String)
                if err != nil {
                    logger.Error("error sending notification to topic", zap.Error(err))
                }

            }
        }
    })
    c.Start()
} 




func NewImpartNotificationService(db *sql.DB, stage, region, platformApplicationARN string, logger *zap.Logger) NotificationService {

    //SNS not available in us-east-2
    if strings.EqualFold(region, "us-east-2") {
        region = "us-east-1"
    }
    sess, err := session.NewSession(&aws.Config{
        Region:     aws.String(region),
        HTTPClient: NewHttpClient(10 * time.Second),
    })
    if err != nil {
        logger.Fatal("unable to create aws session", zap.Error(err))
    }

    snsAppleNotificationService := &snsAppleNotificationService{
        stage:                  stage,
        Logger:                 logger,
        SNS:                    sns.New(sess),
        platformApplicationARN: platformApplicationARN,
        db:                     db,
    }

    logger.Debug("created new NotificationService",
        zap.String("stage", stage),
        zap.String("arn", platformApplicationARN))

    return snsAppleNotificationService
}

Why I am getting 2 notification at a time ? How can I Solve this

func (ns *snsAppleNotificationService) NotifyTopic(ctx context.Context, data NotificationData, alert Alert, topicARN string) error {
    var b []byte
    var err error
    if strings.TrimSpace(topicARN) == "" {
        return nil
    }

    ns.Logger.Debug("sending push notification",
        zap.Any("data", data),
        zap.Any("msg", alert),
        zap.String("platformEndpoint", topicARN),
        zap.String("arn", ns.platformApplicationARN))

    if b, err = json.Marshal(apnsMessageWrapper{
        APNSData: APNSMessage{
            Alert: alert,
            Sound: aws.String("default"),
            Data:  data,
            Badge: aws.Int(0),
        },
    }); err != nil {
        return err
    }

    msg := awsSNSMessage{Default: *alert.Body}

    msg.APNS = string(b)
    msg.APNSSandbox = string(b)

    if b, err = json.Marshal(msg); err != nil {
        return err
    }

    input := &sns.PublishInput{
        Message:          aws.String(string(b)),
        MessageStructure: aws.String("json"),
        TopicArn:         aws.String(topicARN),
    }
    // print()
    _, err = ns.Publish(input)
    if err != nil {
        ns.Logger.Error("push-notification : After publish input",
            zap.Any("topicARN", topicARN),
            zap.Error(err),
        )
    }
    return err
}

main fuction

func main() {
    logger, err := zap.NewProduction()
    if err != nil {
        log.Fatal(err)
    }
    cfg, err := config.GetImpart()
    if err != nil {
        logger.Fatal("error parsing config", zap.Error(err))
    }
    if cfg == nil {
        logger.Fatal("nil config")
        return
    }

    if cfg.Debug {
        gin.SetMode(gin.DebugMode)
        //boil.DebugMode = true
        boil.WithDebugWriter(context.TODO(), &config.ZapBoilWriter{Logger: logger})
        logger, _ = zap.NewDevelopment()
        if cfg.Env == config.Local || cfg.Env == config.Development {
            logger.Debug("config startup", zap.Any("config", *cfg))
        }
    } else {
        gin.SetMode(gin.ReleaseMode)
    }

    //init the sentry logger ,either debug
    logger, err = impart.InitSentryLogger(cfg, logger, cfg.Debug)
    if err != nil {
        logger.Error("error on sentry init", zap.Any("error", err))
    }

    migrationDB, err := cfg.GetMigrationDBConnection()
    if err != nil {
        logger.Fatal("unable to connect to DB", zap.Error(err))
    }

    //Trap sigterm during migraitons
    migrationsDoneChan := make(chan bool)
    shutdownMigrationsChan := make(chan bool)
    sigc := make(chan os.Signal, 1)
    signal.Notify(sigc,
        syscall.SIGINT,
        syscall.SIGTERM,
        syscall.SIGQUIT)
    go func() {
        select {
        case <-sigc:
            logger.Info("received a shutdown request during migrations, sending shutdown signal")
            shutdownMigrationsChan <- true
        case <-migrationsDoneChan:
            logger.Info("migrations complete, no longer waiting for sig int")
            return
        }
    }()

    err = migrater.RunMigrationsUp(migrationDB, cfg.MigrationsPath, logger, shutdownMigrationsChan)
    if err != nil {
        logger.Fatal("error running migrations", zap.Error(err))
    }
    migrationsDoneChan <- true
    if err := migrationDB.Close(); err != nil {
        logger.Fatal("error closing migrations DB connection", zap.Error(err))
    }

    boil.SetLocation(time.UTC)
    db, err := cfg.GetDBConnection()
    if err != nil {
        logger.Fatal("unable to connect to DB", zap.Error(err))
    }
    defer db.Close()
    defer logger.Sync()

    // if err := migrater.BootStrapAdminUsers(db, cfg.Env, logger); err != nil {
    //  logger.Fatal("unable to bootstrap user", zap.Error(err))
    // }

    // if err := migrater.BootStrapTopicHive(db, cfg.Env, logger); err != nil {
    //  logger.Fatal("unable to bootstrap user", zap.Error(err))
    // }

    // initiate global profanity detector
    impart.InitProfanityDetector(db, logger)
    impart.NotifyWeeklyActivity(db, logger)

    services := setupServices(cfg, db, logger)

    r := gin.New()
    r.Use(CORS)
    r.Use(secure.Secure(secure.Options{
        //AllowedHosts:          []string{"*"},
        // AllowedHosts: []string{"localhost:3000", "ssl.example.com"},
        //SSLRedirect: true,
        // SSLHost:               "*",
        SSLProxyHeaders:       map[string]string{"X-Forwarded-Proto": "https"},
        STSIncludeSubdomains:  true,
        FrameDeny:             true,
        ContentTypeNosniff:    true,
        BrowserXssFilter:      true,
        ContentSecurityPolicy: "default-src 'self'",
    }))
    r.RedirectTrailingSlash = true
    r.Use(ginzap.RecoveryWithZap(logger, true))      // panics don't stop server
    r.Use(ginzap.Ginzap(logger, time.RFC3339, true)) // logs all requests

    r.NoRoute(noRouteFunc)
    r.GET("/ping", func(ctx *gin.Context) {
        _, err := dbmodels.Pings(dbmodels.PingWhere.Ok.EQ(true)).One(ctx, db)
        if err != nil {
            ctx.AbortWithStatus(http.StatusInternalServerError)
        }
        ctx.String(http.StatusOK, "pong")
    })
    var v1Route string
    var v2Route string
    if cfg.Env == config.Production || cfg.Env == config.Local {
        v1Route = "v1"
        v2Route = "v1.1"
    } else {
        v1Route = fmt.Sprintf("%s/v1", cfg.Env)
        v2Route = fmt.Sprintf("%s/v1.1", cfg.Env)
    }
    err = mailchimp.SetKey(impart.MailChimpApiKey)
    if err != nil {
        logger.Info("Error connecting Mailchimp", zap.Error(err),
            zap.Any("MailchimpApikey", cfg.MailchimpApikey))
    }

    v1 := r.Group(v1Route)
    setRouter(v1, services, logger, db)

    v2 := r.Group(v2Route)
    setRouter(v2, services, logger, db)

    server := cfg.GetHttpServer()
    server.Handler = r
    logger.Info("Impart backend started.", zap.Int("port", cfg.Port), zap.String("env", string(cfg.Env)))
    if err := graceful.Graceful(server.ListenAndServe, server.Shutdown); err != nil {
        logger.Fatal("error serving", zap.Error(err))
    }
    logger.Info("done serving")
}

publish

// See also, https://docs.aws.amazon.com/goto/WebAPI/sns-2010-03-31/Publish
func (c *SNS) Publish(input *PublishInput) (*PublishOutput, error) {
    req, out := c.PublishRequest(input)
    return out, req.Send()
}
0

There are 0 best solutions below