Exemplo n.º 1
0
func (m *Master) recHeartbeatEvt() {
	var nextDur time.Duration
	nowSec := time.Now().Second()
	if nowSec > 30 {
		nextDur = time.Duration(90-nowSec) * time.Second
	} else {
		nextDur = time.Duration(30-nowSec) * time.Second
	}

	t1 := time.NewTimer(nextDur)
	for {
		select {
		case <-t1.C:
			catInst := cat.Instance()
			tran := catInst.NewTransaction("System", "Status")
			h := catInst.NewHeartbeat("HeartBeat", util.GetIP())
			combineHeartbeat(h, strconv.Itoa(m.port), heartbeatValues{mapValues: util.GetStatus(), urlValues: nil})
			for _, w := range m.workers {
				combineHeartbeat(h, strconv.Itoa(w.host.GetPort()), w.heartbeatInfo)
			}
			h.SetStatus("0")
			h.Complete()
			tran.SetStatus("0")
			tran.Complete()
			t1.Reset(time.Duration(time.Minute))
		}
	}
}
Exemplo n.º 2
0
func (w *ImageProcessWorker) Start(opt StartOpt) <-chan error {
	if !opt.NewHosting {
		opts := &web.ImageProcessOptions{ListenAddress: fmt.Sprintf("127.0.0.1:%d", w.Port)}
		webHandler := web.NewImageProcessWebHandler(opts)
		util.LogEvent(cat.Instance(), "Reboot", fmt.Sprintf("%s:%d", util.LocalIP(), w.Port), nil)
		go webHandler.Run()
		return webHandler.ListenError()
	} else {
		cmd := exec.Command("go", "run", "imgsvrd.go", "-process.worker", "-port", strconv.Itoa(w.Port))
		err := cmd.Start()
		if err != nil {
			log.Errorf("start worker=%d failed. error=%s", w.Port, err.Error())
			util.LogErrorEvent(cat.Instance(), "DaemonProcess.StartWorkerError", err.Error())
			w.startErrCh <- err
		}
	}
	return w.startErrCh
}
Exemplo n.º 3
0
func (m *Master) recRebootEvt() {
	cat := cat.Instance()
	tran := cat.NewTransaction("System", "Reboot")
	defer func() {
		tran.SetStatus("0")
		tran.Complete()
	}()
	util.LogEvent(cat, "Reboot", util.JoinString(util.GetIP(), ":", strconv.Itoa(m.port)), nil)
}
Exemplo n.º 4
0
func (p *ScaleProcessor) Process(img *img4g.Image) error {
	log.Debug("process scale")
	var err error
	tran := cat.Instance().NewTransaction("Command", "Scale")
	defer func() {
		tran.SetStatus(err)
		tran.Complete()
	}()
	err = img.Resize(p.Width, p.Height)
	return err
}
Exemplo n.º 5
0
func View(this *ViewController, loadImgRequest *request.LoadImgRequest) {
	var result = util.Error{}
	Cat := cat.Instance()
	title := "/fdupload/target"
	if loadImgRequest.IsSource {
		title = "/fdupload/source"
	}
	tran := Cat.NewTransaction("URL", title)
	defer func() {
		if p := recover(); p != nil {
			Cat.LogPanic(p)
		}
		if result.Err != nil {
			tran.SetStatus(result.Err)
		} else {
			tran.SetStatus("0")
		}
		tran.Complete()
	}()
	util.LogEvent(Cat, "URL", "URL.Client", map[string]string{
		"clientip": util.GetClientIP(this.Ctx.Request),
		"serverip": util.GetIP(),
		"proto":    this.Ctx.Request.Proto,
		"referer":  this.Ctx.Request.Referer(),
		//"agent":    request.UserAgent(),
	})
	util.LogEvent(Cat, "URL", "URL.Method", map[string]string{
		"Http": this.Ctx.Request.Method + " " + loadImgRequest.FilePath,
	})

	imgRequest := business.ImageRequest{}
	imgRequest.Cat = Cat
	resp, e := imgRequest.Download(loadImgRequest)

	if e.Err != nil {
		this.Ctx.WriteString(e.Err.(error).Error())
	} else {
		//this.Ctx.Output.ContentType("image/Jpeg")

		//this.Ctx.Output.Body(resp.FileBytes)
		bts, err := soapparse.B64.DecodeString(string(resp.FileBytes))
		if err != nil {
			this.Ctx.WriteString(err.Error())
		} else {
			this.Ctx.Output.Header("Content-Type", "image/jpeg")
			this.Ctx.Output.Body(bts)
		}
	}
}
Exemplo n.º 6
0
func main() {
	ConfigCat()
	InitDB()
	func() {
		Reboot := "Reboot"
		Cat := cat.Instance()
		tran := Cat.NewTransaction("System", Reboot)
		defer func() {
			tran.SetStatus("0")
			tran.Complete()
		}()
	}()
	go LogHeartbeat()
	beego.Run()
}
Exemplo n.º 7
0
func (m *Master) checkWorkerHealth(w *Worker) {
	val, err := doHttpCall(util.JoinString(
		"http://127.0.0.1:", strconv.Itoa(w.host.GetPort()), "/heartbeat/"))
	if err != nil {
		w.sick()
		log.WithFields(log.Fields{
			"port": w.host.GetPort(),
			"type": "WorkerProcess.HeartbeatError",
		}).Error(err.Error())
		util.LogErrorEvent(cat.Instance(), "WorkerProcess.HeartbeatError", err.Error())
	} else {
		w.healthy()
		url, err := url.Parse(string(val))
		if err != nil {
			log.Errorf("parse heartbeat from worker=%d failed.", w.host.GetPort())
		} else {
			w.heartbeatInfo = heartbeatValues{mapValues: nil, urlValues: url.Query()}
		}
	}
}
Exemplo n.º 8
0
func (m *Master) killDeadWorkerAndStartNew(w *Worker) bool {
	isDead := w.isDead()
	if isDead {
		log.Debugf("find worker=%d is dead, prepared to restart", w.host.GetPort())
		err := killPort(w.host.GetPort())
		if err != nil {
			log.WithFields(log.Fields{
				"port": w.host.GetPort(),
				"type": "DaemonProcess.KillProcessError",
			}).Error(err.Error())
			util.LogErrorEvent(cat.Instance(), "DaemonProcess.KillProcessError", err.Error())
		} else {
			log.Infof("kill worker=%d ok.", w.host.GetPort())
		}
		w.host.Start(StartOpt{NewHosting: true})
		log.Debugf("restart worker=%d ok.", w.host.GetPort())
		w.healthy()
	}
	return isDead
}
Exemplo n.º 9
0
func (h *ImageProcessHandler) handle(w http.ResponseWriter, r *http.Request) {
	var (
		err        error
		commandArg *command.CommandArgument
		handleOk   = true
		rootCtx    = route.Context(r)
		imagePath  = route.Param(rootCtx, "imagepath")
		catVar     = cat.Instance()
		catTran    = catVar.NewTransaction("URL", getShortImagePath(imagePath))
		ctxWithCat = context.WithValue(rootCtx, "cat", catVar)
	)
	defer postHandle(catVar, catTran, imagePath, w, &err, &handleOk)
	h.recUrlEvt(catVar, imagePath, r)
	commandArg, err = command.Parse(ctxWithCat)
	if err != nil {
		return
	}

	//arg,  := command.Parse(catCtx)
}
Exemplo n.º 10
0
func LogHeartbeat() {
	defer func() {
		if err := recover(); err != nil {
			//log.Error(fmt.Sprintf("%v", err))
			LogHeartbeat()
		}
	}()

	ip := util.GetIP()
	second := time.Now().Second()
	if second < 29 {
		sleep := time.Duration((29 - second) * 1000000000)
		time.Sleep(sleep)
	}

	catinstance := cat.Instance()
	for {
		//log.Debug("send cat heartbeat")
		stats := util.GetStatus()
		tran := catinstance.NewTransaction("System", "Status")
		h := catinstance.NewHeartbeat("HeartBeat", ip)
		for key, value := range stats {
			switch key {
			case "Alloc", "TotalAlloc", "Sys", "Mallocs", "Frees", "OtherSys", "PauseNs":
				h.Set("System", key, value)
			case "HeapAlloc", "HeapSys", "HeapIdle", "HeapInuse", "HeapReleased", "HeapObjects":
				h.Set("HeapUsage", key, value)
			case "NextGC", "LastGC", "NumGC":
				h.Set("GC", key, value)
			}
		}
		h.SetStatus("0")
		h.Complete()
		tran.SetStatus("0")
		tran.Complete()
		second = time.Now().Second()
		sleep := time.Duration((90 - second) * 1000000000)
		time.Sleep(sleep)
	}
}
Exemplo n.º 11
0
func (handler *LogoWS) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	Cat := cat.Instance()
	w.Header().Set("Connection", "keep-alive")
	w.Header().Set("Content-Type", "text/xml")

	tran := Cat.NewTransaction("URL", "LogoWs.asmx")
	util.LogEvent(Cat, "URL", "URL.Client", map[string]string{
		"clientip": util.GetClientIP(r),
		"serverip": util.GetIP(),
		"proto":    r.Proto,
		"referer":  r.Referer(),
		//"agent":    request.UserAgent(),
	})
	var result util.Error
	defer func() {
		if p := recover(); p != nil {
			Cat.LogPanic(p)
		}
		if result.Err != nil && !result.IsNormal {
			tran.SetStatus(result.Err)
		} else {
			tran.SetStatus("0")
		}
		tran.Complete()
	}()

	bts, err := ioutil.ReadAll(r.Body)
	if err != nil {
		util.LogErrorEvent(Cat, "RequestReadError", err.Error())
		result = util.Error{IsNormal: false, Err: err, Type: "RequestReadError"}

		return
	}
	req := request.Request{}
	result = EncodeRequest(Cat, bts, &req)
	if result.Err != nil && !result.IsNormal {
		//writeResponse(w, []byte(result.Type))
		return
	}

	var (
		resp        interface{}
		header      *response.Header
		e           util.Error
		logoRequest = business.LogoRequest{
			ImageRequest: business.ImageRequest{
				Cat: Cat,
			},
			FontSizes: []int{14, 16, 18, 20},
		}
	)

	requestTran := Cat.NewTransaction("Request", "SaveLogo")
	defer func() {
		if p := recover(); p != nil {
			Cat.LogPanic(p)
		}
		if result.Err != nil && !result.IsNormal {
			requestTran.SetStatus(result.Err)
		} else {
			requestTran.SetStatus("0")
		}
		requestTran.Complete()
	}()

	resp, result = logoRequest.Save(&req.SaveRequest)

	if result.Err != nil {
		header = createFailHeader(req.Header, fmt.Sprintf("%v", result.Err))
	} else {
		header = transformHeader(req.Header, RESULTCODE_SUCCESS, "")
	}
	content, e := DecodeResponse(Cat, header, resp)
	if e.Err != nil {
		result = e
		writeResponse(w, []byte(result.Err.(error).Error()))
	} else {
		writeResponse(w, content)
	}

	//content, err := soapparse.DecResp(header, resp) //
	//if err != nil {
	//	return
	//}
	//writeResponse(w, content)
}
Exemplo n.º 12
0
func main() {
	CAT := cat.Instance()
	i, _ := im4g.NewImageAsPNG(100, 100, CAT)
	ioutil.WriteFile("1.png", i.Blob, 0644)
}
Exemplo n.º 13
0
func (handler *ImageWS) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	defer r.Body.Close()
	w.Header().Set("Connection", "keep-alive")
	w.Header().Set("Content-Type", "text/xml")

	Cat := cat.Instance()
	tran := Cat.NewTransaction("URL", "ImageWs.asmx")
	util.LogEvent(Cat, "URL", "URL.Client", map[string]string{
		"clientip": util.GetClientIP(r),
		"serverip": util.GetIP(),
		"proto":    r.Proto,
		"referer":  r.Referer(),
		//"agent":    request.UserAgent(),
	})
	var result util.Error
	defer func() {
		if p := recover(); p != nil {
			Cat.LogPanic(p)
		}
		if result.Err != nil && !result.IsNormal {
			tran.SetStatus(result.Err)

		} else {
			tran.SetStatus("0")
		}
		tran.Complete()
	}()
	bts, err := ioutil.ReadAll(r.Body)
	if err != nil {
		util.LogErrorEvent(Cat, "RequestReadError", err.Error())
		result = util.Error{IsNormal: false, Err: err, Type: "RequestReadError"}
		msg := []byte(err.Error())
		writeResponse(w, msg)
		return
	}
	req := request.Request{}
	result = EncodeRequest(Cat, bts, &req)
	if result.Err != nil && !result.IsNormal {
		writeResponse(w, []byte(result.Type))
		return
	}
	var (
		resp       interface{}
		header     *response.Header
		e          util.Error
		imgRequest = business.ImageRequest{Cat: Cat}
	)

	requestTran := Cat.NewTransaction("Request", strings.Replace(req.Header.RequestType, "Arch.Base.ImageWS.", "", -1))
	defer func() {
		if p := recover(); p != nil {
			Cat.LogPanic(p)
		}
		if result.Err != nil && !result.IsNormal {
			requestTran.SetStatus(result.Err)
		} else {
			requestTran.SetStatus(CATTRANSUCCESS)
		}
		requestTran.Complete()
	}()

	switch req.Header.RequestType {
	case REQUESTTYPE_SAVEIMAGE:
		resp, e = imgRequest.Save(&req.SaveRequest)
	case REQUESTTYPE_LOADIMAGE:
		resp, e = imgRequest.Download(&req.LoadImgRequest)
	case REQUESTTYPE_LOADZIP:
		resp, e = imgRequest.DownloadZip(&req.LoadZipRequest)
	case REQUESTTYPE_DELETEIMAGE:
		resp, e = imgRequest.Delete(&req.DeleteRequest)
	default:
		util.LogErrorEvent(Cat, "RequestTypeInvalid", req.Header.RequestType)
		e = util.Error{IsNormal: true, Err: errors.New("requesttype is invalid!"), Type: "RequestTypeInvalid"}
	}
	if e.Err != nil {
		result = e
		header = createFailHeader(req.Header, fmt.Sprintf("%v", e.Err))
	} else {
		header = transformHeader(req.Header, RESULTCODE_SUCCESS, "")
	}
	content, e := DecodeResponse(Cat, header, resp)
	if e.Err != nil {
		result = e
		writeResponse(w, []byte(result.Err.(error).Error()))
	} else {
		writeResponse(w, content)
	}
}
Exemplo n.º 14
0
func (this *HostProcessor) Run() {
	hostPort = strconv.Itoa(this.Port)
	threadcount := strconv.Itoa(this.ThreadCount)
	log.WithFields(log.Fields{
		"hostPort":    hostPort,
		"threadCount": threadcount,
		"nginxPath":   this.NginxPath,
		"nginxPort":   this.NginxPort,
	}).Debug("run host process")

	defer func() {
		if p := recover(); p != nil {
			log.WithFields(log.Fields{
				"hostPort":    hostPort,
				"threadCount": threadcount,
				"type":        "DaemonProcess.RunPanic",
			}).Error(fmt.Sprintf("%v", p))
			LogErrorEvent(CatInstance, "DaemonProcess.RunPanic", fmt.Sprintf("%v", p))
		}
		os.Exit(2)
	}()
	func() {
		Cat := cat.Instance()
		tran := Cat.NewTransaction("System", Reboot)
		defer func() {
			tran.SetStatus("0")
			tran.Complete()
		}()
		LogEvent(Cat, Reboot, JoinString(GetIP(), ":", hostPort), nil)
	}()

	this.computePorts()
	if this.NginxPath != "" {
		if err := ModifyNginxconf(this.NginxPath, this.NginxPort, ports); err != nil {
			log.WithFields(log.Fields{
				"nginxPath": this.NginxPath,
				"nginxPort": this.NginxPort,
				"type":      "DaemonProcess.ModifyNginxError",
			}).Error(err.Error())
			LogErrorEvent(CatInstance, "DaemonProcess.ModifyNginxError", err.Error())
			return
		}
		if err := RestartNginx(this.NginxPath); err != nil {
			log.WithFields(log.Fields{
				"nginxPath": this.NginxPath,
				"type":      "DaemonProcess.RestartNginxError",
			}).Error(err.Error())
			LogErrorEvent(CatInstance, "DaemonProcess.RestartNginxError", err.Error())
			return
		}
	}

	portstats = make(map[string]url.Values)
	for p, _ := range ports {
		this.startWorkerProcess(p)
		log.WithFields(log.Fields{
			"port": p,
		}).Debug("run subproccess on port")
	}

	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt, os.Kill)
	go this.monitorWorkerProcesses()
	go this.sendCatHeartBeat()
	go this.listenHeartbeat()
	<-c //Interupt signal coming
	os.Exit(0)
}
Exemplo n.º 15
0
func init() {
	util.InitCat()
	CatInstance = cat.Instance()
}
Exemplo n.º 16
0
func init() {
	util.InitCat()
	globalCat = cat.Instance()
}
Exemplo n.º 17
0
func (handler *Handler) ServeHTTP(writer http.ResponseWriter, request *http.Request) {
	Cat := cat.Instance()
	handler.ChainBuilder = &ProcChainBuilder{Cat}
	uri := request.URL.String()
	tran := Cat.NewTransaction("URL", getShortUri(uri))
	var (
		err       error
		isSuccess bool = true
	)
	defer func() {
		p := recover()
		if p != nil {
			logErrWithUri(uri, fmt.Sprintf("%v", p), "errorLevel")
			Cat.LogPanic(p)
			tran.SetStatus(p)
		}

		if isSuccess {
			tran.SetStatus("0")
			tran.Complete()
		} else {
			tran.SetStatus(err)
			tran.Complete()
		}
		if p != nil || err != nil {
			http.Error(writer, http.StatusText(404), 404)
		}
	}()

	LogEvent(Cat, "URL", "URL.Client", map[string]string{
		"clientip": util.GetClientIP(request),
		"serverip": util.GetIP(),
		"proto":    request.Proto,
		"referer":  request.Referer(),
		//"agent":    request.UserAgent(),
	})

	LogEvent(Cat, "URL", "URL.Method", map[string]string{
		"Http": request.Method + " " + uri,
	})

	LogEvent(Cat, "UpstreamProcess", JoinString(GetIP(), ":", WorkerPort), nil)

	isDigimarkUrl := false
	params, ok1 := legalUrl.FindStringSubmatchMap(uri)
	if !ok1 {
		params, ok1 = digimarkUrl.FindStringSubmatchMap(uri)
		if ok1 {
			isDigimarkUrl = true
		} else {
			err = errors.New("URI.ParseError")
			logErrWithUri(uri, err.Error(), "warnLevel")
			LogErrorEvent(Cat, "URI.ParseError", "")
			return
		}
	}

	//parse storage from url parameters
	store, storagetype, err1 := FindStorage(params, Cat)
	if err1 != nil {
		err = errors.New("Storage.ParseError")
		logErrWithUri(uri, err1.Error(), "warnLevel")
		LogErrorEvent(Cat, "Storage.ParseError", err1.Error())
		return
	}
	//parse handlers chain from url parameters
	var chain *proc.ProcessorChain = nil
	var buildErr *buildError = nil
	if isDigimarkUrl == true {
		chain, buildErr = handler.ChainBuilder.DigimarkProcChain(params)
	} else {
		chain, buildErr = handler.ChainBuilder.Build(params)
	}
	if buildErr != nil {
		err = errors.New(buildErr.Type())
		logErrWithUri(uri, buildErr.Error(), "warnLevel")
		LogErrorEvent(Cat, buildErr.Type(), buildErr.Error())
		return
	}
	//download image from storage
	var bts []byte
	func() {
		type storageError interface {
			Error() string
			Normal() bool //is normal error?
			Type() string //error type
		}

		var err1 error
		getimagetran := Cat.NewTransaction("Storage", storagetype)
		defer func() {
			if err1 != nil {
				logErrWithUri(uri, err1.Error(), "errorLevel")
				e, ok := err1.(storageError)
				if ok && e.Normal() {
					err = errors.New(fmt.Sprintf("%v.%v", storagetype, e.Type()))
					LogErrorEvent(Cat, fmt.Sprintf("%v.%v", storagetype, e.Type()), e.Error())
				} else {
					err = errors.New(storagetype + ".UnExpectedError")
					LogErrorEvent(Cat, err.Error(), err1.Error())
					isSuccess = false
				}
			} else if len(bts) == 0 {
				err = errors.New(storagetype + ".ImgLenZero")
				LogErrorEvent(Cat, err.Error(), "recv image length is 0")
				logErrWithUri(uri, "recv image length is 0", "warnLevel")
			}
			if isSuccess {
				getimagetran.SetStatus("0")
			} else {
				getimagetran.SetStatus(err)
			}
			getimagetran.Complete()
		}()
		bts, err1 = store.GetImage()
	}()
	if err != nil {
		return
	}
	size := len(bts)
	sizestr := strconv.Itoa(size)
	tran.AddData("size", sizestr)
	Cat.LogEvent("Size", GetImageSizeDistribution(size))

	log.WithFields(log.Fields{
		"size": size,
		"uri":  uri,
	}).Debug("recv image length")
	format, _ := params["ext"]
	img := &img4g.Image{Blob: bts, Format: format, Cat: Cat}

	rspChan := make(chan bool, 1)
	task := &nepheleTask{inImg: img, chain: chain, rspChan: rspChan, CatInstance: Cat, canceled: false}
	taskChan <- task

	select {
	case ok := <-rspChan:
		if !ok {
			err = errors.New("ProcessError")
			isSuccess = false
			logErrWithUri(uri, err.Error(), "errorLevel")
			return
		}
	case <-time.After(time.Second * 5):
		task.SetCanceled()
		err = errors.New("ProcessTimeout")
		logErrWithUri(uri, err.Error(), "errorLevel")
		isSuccess = false
		LogErrorEvent(Cat, "ProcessTimeout", "")
		return
	}

	writer.Header().Set("Content-Type", "image/"+format)
	writer.Header().Set("Content-Length", strconv.Itoa(len(img.Blob)))
	writer.Header().Set("Last-Modified", "2015/1/1 01:01:01")
	log.WithFields(log.Fields{
		"size": size,
		"uri":  uri,
	}).Debug("final image size")
	if _, err1 = writer.Write(img.Blob); err1 != nil {
		logErrWithUri(uri, err1.Error(), "errorLevel")
		err = errors.New("Response.WriteError")
		LogErrorEvent(Cat, "Response.Writeerror", err1.Error())
		isSuccess = false
	}
}
Exemplo n.º 18
0
func (this *HostProcessor) sendCatHeartBeat() {
	defer func() {
		if err := recover(); err != nil {
			log.Error(fmt.Sprintf("%v", err))
			this.sendCatHeartBeat()
		}
	}()
	ip := GetIP()
	second := time.Now().Second()
	if second < 29 {
		sleep := time.Duration((29 - second) * 1000000000)
		time.Sleep(sleep)
	}

	catinstance := cat.Instance()
	for {
		log.Debug("send cat heartbeat")
		stats1 := util.GetStatus()
		data := url.Values{}
		data.Add("port", hostPort)
		for k, v := range stats1 {
			data.Add(k, v)
		}
		portstats[hostPort] = data

		tran := catinstance.NewTransaction("System", "Status")
		h := catinstance.NewHeartbeat("HeartBeat", ip)
		for _, heart := range portstats {
			if heart == nil {
				continue
			}
			port := heart.Get("port")
			if port == "" {
				continue
			}
			h.Set("System", JoinString("Alloc_", port), heart.Get("Alloc"))
			h.Set("System", JoinString("TotalAlloc_", port), heart.Get("TotalAlloc"))
			h.Set("System", JoinString("Sys_", port), heart.Get("Sys"))
			h.Set("System", JoinString("Mallocs_", port), heart.Get("Mallocs"))
			h.Set("System", JoinString("Frees_", port), heart.Get("Frees"))
			h.Set("System", JoinString("OtherSys_", port), heart.Get("OtherSys"))
			h.Set("System", JoinString("PauseNs_", port), heart.Get("PauseNs"))

			h.Set("HeapUsage", JoinString("HeapAlloc_", port), heart.Get("HeapAlloc"))
			h.Set("HeapUsage", JoinString("HeapSys_", port), heart.Get("HeapSys"))
			h.Set("HeapUsage", JoinString("HeapIdle_", port), heart.Get("HeapIdle"))
			h.Set("HeapUsage", JoinString("HeapInuse_", port), heart.Get("HeapInuse"))
			h.Set("HeapUsage", JoinString("HeapReleased_", port), heart.Get("HeapReleased"))
			h.Set("HeapUsage", JoinString("HeapObjects_", port), heart.Get("HeapObjects"))

			h.Set("GC", JoinString("NextGC_", port), heart.Get("NextGC"))
			h.Set("GC", JoinString("LastGC_", port), heart.Get("LastGC"))
			h.Set("GC", JoinString("NumGC_", port), heart.Get("NumGC"))
			portstats[port] = nil
		}
		h.SetStatus("0")
		h.Complete()
		tran.SetStatus("0")
		tran.Complete()
		second = time.Now().Second()
		sleep := time.Duration((90 - second) * 1000000000)
		time.Sleep(sleep)
	}
}