func waitForNotification(l *pq.Listener) { for { select { case notify := <-l.Notify: payload := strings.SplitN(notify.Extra, "|", 3) id, err := strconv.ParseInt(payload[0], 10, 64) if err != nil { panic(err) } var roomId int64 roomId, err = strconv.ParseInt(payload[1], 10, 64) if err != nil { panic(err) } msg := models.GetMessage(id) revel.INFO.Printf("received notification with payload: '%d' '%d' '%s' '%s'\n", msg.Id, msg.RoomId, msg.Text, msg.ImageUrl) Publish(EVENT_MSG, int64(roomId), *msg) case <-time.After(200 * time.Millisecond): go func() { if err := l.Ping(); err != nil { panic(err) } }() } } }
func waitForNotification(l *pq.Listener) { for { select { case n := <-l.Notify: fmt.Println("Received data from channel [", n.Channel, "] :") // Prepare notification payload for pretty print var prettyJSON bytes.Buffer err := json.Indent(&prettyJSON, []byte(n.Extra), "", "\t") if err != nil { fmt.Println("Error processing JSON: ", err) return } fmt.Println(string(prettyJSON.Bytes())) return case <-time.After(90 * time.Second): fmt.Println("Received no events for 90 seconds, checking connection") go func() { l.Ping() }() return } } }
"github.com/tedsuo/ifrit" "github.com/tedsuo/ifrit/ginkgomon" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" . "github.com/sclevine/agouti/matchers" "github.com/cloudfoundry/gunk/urljoiner" "github.com/concourse/atc" "github.com/concourse/atc/db" "github.com/concourse/atc/event" ) var _ = Describe("One-off Builds", func() { var atcProcess ifrit.Process var dbListener *pq.Listener var atcPort uint16 var pipelineDBFactory db.PipelineDBFactory BeforeEach(func() { dbLogger := lagertest.NewTestLogger("test") postgresRunner.Truncate() dbConn = postgresRunner.Open() dbListener = pq.NewListener(postgresRunner.DataSourceName(), time.Second, time.Minute, nil) bus := db.NewNotificationsBus(dbListener, dbConn) sqlDB = db.NewSQL(dbLogger, dbConn, bus) pipelineDBFactory = db.NewPipelineDBFactory(dbLogger, dbConn, bus, sqlDB) atcProcess, atcPort = startATC(atcBin, 1) })
import ( "time" "github.com/concourse/atc/db" "github.com/concourse/atc/db/fakes" "github.com/lib/pq" "github.com/pivotal-golang/lager/lagertest" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" ) var _ = Describe("PipelineDBFactory", func() { var dbConn db.Conn var listener *pq.Listener var pipelineDBFactory db.PipelineDBFactory var pipelinesDB *fakes.FakePipelinesDB BeforeEach(func() { postgresRunner.Truncate() dbConn = db.Wrap(postgresRunner.Open()) listener = pq.NewListener(postgresRunner.DataSourceName(), time.Second, time.Minute, nil) Eventually(listener.Ping, 5*time.Second).ShouldNot(HaveOccurred()) bus := db.NewNotificationsBus(listener, dbConn) pipelinesDB = new(fakes.FakePipelinesDB)
"github.com/lib/pq" "github.com/pivotal-golang/lager/lagertest" "github.com/tedsuo/ifrit" "github.com/tedsuo/ifrit/ginkgomon" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "github.com/onsi/gomega/gexec" "github.com/concourse/atc" "github.com/concourse/atc/db" ) var _ = Describe("Auth", func() { var atcProcess ifrit.Process var dbListener *pq.Listener var atcPort uint16 BeforeEach(func() { logger := lagertest.NewTestLogger("test") postgresRunner.CreateTestDB() dbConn = postgresRunner.Open() dbListener = pq.NewListener(postgresRunner.DataSourceName(), time.Second, time.Minute, nil) bus := db.NewNotificationsBus(dbListener) sqlDB = db.NewSQL(logger, dbConn, bus) _, err := sqlDB.SaveConfig(atc.DefaultPipelineName, atc.Config{}, db.ConfigVersion(1), db.PipelineUnpaused) Ω(err).ShouldNot(HaveOccurred()) atcBin, err := gexec.Build("github.com/concourse/atc/cmd/atc") Ω(err).ShouldNot(HaveOccurred())
func setupDatabaseListener() { if !checkDatabaseHandleValid(db) { return } //create/replace function for notifyPhoneNumber() if _, err := db.Exec(`CREATE or REPLACE FUNCTION notifyPhoneNumber() RETURNS trigger AS $$ BEGIN IF TG_OP='DELETE' THEN EXECUTE FORMAT('NOTIFY notifyphonenumber, ''%s''', OLD.PhoneNumber); ELSE EXECUTE FORMAT('NOTIFY notifyphonenumber, ''%s''', NEW.PhoneNumber); END IF; RETURN NULL; END; $$ LANGUAGE plpgsql;`); err != nil { log.Println(err) } else { log.Println("Successfully create/replace function notifyPhoneNumber()") } //check for trigger existence var triggerExist bool if err := db.QueryRow(`SELECT EXISTS( SELECT 1 FROM pg_trigger WHERE tgname='inprogresschange')`).Scan(&triggerExist); err != nil { log.Println(err) } if !triggerExist { if _, err := db.Exec(`CREATE TRIGGER inprogresschange AFTER INSERT OR UPDATE OR DELETE ON inprogress FOR EACH ROW EXECUTE PROCEDURE notifyPhoneNumber();`); err != nil { log.Println(err) } else { log.Println("Successfully create trigger inprogresschange") } } else { log.Println("Trigger inprogresschange exists.") } //Create handler for logging listener errors reportProblem := func(ev pq.ListenerEventType, err error) { if err != nil { fmt.Println(err.Error()) } } //Listen for table updates var listenerObj *pq.Listener listenerObj = pq.NewListener(os.Getenv("DATABASE_URL"), 10*time.Second, time.Minute, reportProblem) err := listenerObj.Listen("notifyphonenumber") if err != nil { log.Println(err) } //Find our session PID so we can ignore notifications from ourselves var pid int fmt.Println("Getting session PID...") if rows, err := db.Query(`SELECT * FROM pg_stat_activity WHERE pid = pg_backend_pid();`); err != nil { log.Println(err) } else { var i interface{} //empty interface to read unneeded columns into for rows.Next() { if err := rows.Scan(&i, &i, &pid, &i, &i, &i, &i, &i, &i, &i, &i, &i, &i, &i, &i, &i, &i, &i); err != nil { log.Println(err) } else { fmt.Println("Session PID:", pid) } } } //Monitor for noitification in background go func() { for { var notificationObj *pq.Notification notificationObj = <-listenerObj.Notify fmt.Printf("Backend PID %v\nChannel %v\nPayload %v\n", notificationObj.BePid, notificationObj.Channel, notificationObj.Extra) //Get updated row from database if the notifying PID is not this instance's PID if pid != notificationObj.BePid { if updatedRows := selectRowsFromTableByPhoneNumber("inprogress", notificationObj.Extra); updatedRows == nil { log.Println(err) } else { //We handle the possibility of deleted rows in laod pickups rows into memory since we can only enumerate over rows object once loadPickupRowsIntoMemory(&pickups, updatedRows, notificationObj) } } } }() }