1.4.5.2
This commit is contained in:
161
EdgeNode/internal/js/isolate_pool.go
Normal file
161
EdgeNode/internal/js/isolate_pool.go
Normal file
@@ -0,0 +1,161 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
//go:build script
|
||||
// +build script
|
||||
|
||||
package js
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeNode/internal/remotelogs"
|
||||
"github.com/TeaOSLab/EdgeNode/internal/utils/goman"
|
||||
memutils "github.com/TeaOSLab/EdgeNode/internal/utils/mem"
|
||||
"github.com/iwind/TeaGo/Tea"
|
||||
"time"
|
||||
)
|
||||
|
||||
type IsolatePool struct {
|
||||
hotIsolates []*Isolate // 当前正在使用的isolates
|
||||
|
||||
coldIsolates []*Isolate // 等待回收的isolates
|
||||
coldTicker *time.Ticker
|
||||
coldIndex int
|
||||
|
||||
maxSize int
|
||||
|
||||
index int
|
||||
}
|
||||
|
||||
func NewIsolatePool(maxSize int) (*IsolatePool, error) {
|
||||
if maxSize <= 0 {
|
||||
maxSize = 1
|
||||
}
|
||||
if maxSize > 512 {
|
||||
maxSize = 512
|
||||
}
|
||||
var pool = &IsolatePool{
|
||||
hotIsolates: make([]*Isolate, maxSize),
|
||||
maxSize: maxSize,
|
||||
}
|
||||
|
||||
err := pool.init()
|
||||
if err != nil {
|
||||
remotelogs.Error("SCRIPT", "create isolate pool failed: "+err.Error())
|
||||
pool.Dispose()
|
||||
return nil, err
|
||||
}
|
||||
return pool, nil
|
||||
}
|
||||
|
||||
func NewAutoIsolatePool() (*IsolatePool, error) {
|
||||
// 每 512M 内存一个isolate
|
||||
var totalMemory = memutils.SystemMemoryGB()
|
||||
var count = totalMemory * 2
|
||||
if count <= 0 {
|
||||
count = 2
|
||||
}
|
||||
|
||||
// 防止在有些系统上OOM
|
||||
if count > 256 {
|
||||
count = 256
|
||||
}
|
||||
return NewIsolatePool(count)
|
||||
}
|
||||
|
||||
func (this *IsolatePool) init() error {
|
||||
for i := 0; i < this.maxSize; i++ {
|
||||
isolate, err := NewIsolate()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
this.hotIsolates[i] = isolate
|
||||
}
|
||||
|
||||
// run init functions
|
||||
if len(this.hotIsolates) > 0 {
|
||||
var isolate = this.hotIsolates[0]
|
||||
ctx, err := isolate.GetContext()
|
||||
if err == nil {
|
||||
_, err = ctx.Run("gojs.runOnce()", "utils.js")
|
||||
if err != nil {
|
||||
remotelogs.Error("SCRIPT", "run once functions failed: "+err.Error())
|
||||
}
|
||||
isolate.PutContext(ctx)
|
||||
}
|
||||
}
|
||||
|
||||
this.coldTicker = time.NewTicker(5 * time.Second)
|
||||
if Tea.IsTesting() {
|
||||
this.coldTicker = time.NewTicker(5 * time.Second)
|
||||
}
|
||||
goman.New(func() {
|
||||
for range this.coldTicker.C {
|
||||
this.tick()
|
||||
}
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (this *IsolatePool) tick() {
|
||||
// dispose cold isolates
|
||||
if len(this.coldIsolates) > 0 {
|
||||
var newIndex = -1
|
||||
for index, coldIsolate := range this.coldIsolates {
|
||||
if coldIsolate.IsUsing() {
|
||||
break
|
||||
}
|
||||
newIndex = index
|
||||
coldIsolate.Dispose()
|
||||
}
|
||||
|
||||
if newIndex >= 0 {
|
||||
this.coldIsolates = this.coldIsolates[newIndex+1:]
|
||||
}
|
||||
}
|
||||
|
||||
// add new isolate
|
||||
if this.coldIndex > this.maxSize-1 {
|
||||
this.coldIndex = 0
|
||||
}
|
||||
var oldIsolate = this.hotIsolates[this.coldIndex]
|
||||
if oldIsolate.OverUses() {
|
||||
newIsolate, err := NewIsolate()
|
||||
if err != nil {
|
||||
remotelogs.Error("SCRIPT", "create isolate failed: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
this.hotIsolates[this.coldIndex] = newIsolate
|
||||
|
||||
this.coldIsolates = append(this.coldIsolates, oldIsolate)
|
||||
}
|
||||
|
||||
this.coldIndex++
|
||||
}
|
||||
|
||||
func (this *IsolatePool) GetContext() (*Context, error) {
|
||||
this.index++ // 不需要加锁,这里没必要非常严格
|
||||
var index = this.index
|
||||
if index >= this.maxSize {
|
||||
index = 0
|
||||
this.index = 0
|
||||
}
|
||||
|
||||
// TODO 未来实现循环查找可用的context,防止因单个context执行时间过长,阻塞整个isolate
|
||||
return this.hotIsolates[index].GetContext()
|
||||
}
|
||||
|
||||
func (this *IsolatePool) PutContext(ctx *Context) {
|
||||
if ctx != nil {
|
||||
ctx.Isolate().PutContext(ctx)
|
||||
}
|
||||
}
|
||||
|
||||
func (this *IsolatePool) MaxSize() int {
|
||||
return this.maxSize
|
||||
}
|
||||
|
||||
func (this *IsolatePool) Dispose() {
|
||||
for _, isolate := range this.hotIsolates {
|
||||
isolate.Dispose()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user