Skip to content

Commit 83cc751

Browse files
committed
refactor(worker): 改进随机数生成并优化任务处理结构
使用crypto/rand替代math/rand生成更安全的随机盐值 重构Worker和Task结构体字段顺序,提高可读性 提取selectWorker方法复用worker选择逻辑 统一使用ServiceUnavailableMsg常量
1 parent ed31201 commit 83cc751

5 files changed

Lines changed: 88 additions & 82 deletions

File tree

.github/workflows/release.yml

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,11 @@ jobs:
4242
npm install go-server-sdk@${{ steps.get_version.outputs.VERSION }}
4343
```
4444
45+
**Rust SDK:**
46+
```bash
47+
cargo add go-server-sdk@${{ steps.get_version.outputs.VERSION }}
48+
```
49+
4550
**Go SDK:**
4651
```bash
4752
go get github.com/go-enols/go-server@${{ steps.get_version.outputs.VERSION }}
@@ -55,6 +60,7 @@ jobs:
5560
5661
- [PyPI Package](https://pypi.org/project/go-server-sdk/${{ steps.get_version.outputs.VERSION }}/)
5762
- [NPM Package](https://www.npmjs.com/package/go-server-sdk/v/${{ steps.get_version.outputs.VERSION }})
63+
- [Crates.io Package](https://crates.io/crates/go-server-sdk/${{ steps.get_version.outputs.VERSION }})
5864
- [Documentation](https://github.com/go-enols/go-server/blob/main/README.md)
5965
draft: false
6066
prerelease: false
@@ -147,6 +153,12 @@ jobs:
147153
node-version: '18'
148154
registry-url: 'https://registry.npmjs.org'
149155

156+
- name: Set up Rust
157+
uses: actions-rs/toolchain@v1
158+
with:
159+
toolchain: stable
160+
override: true
161+
150162
- name: Install Python build dependencies
151163
run: |
152164
python -m pip install --upgrade pip
@@ -167,4 +179,12 @@ jobs:
167179
npm ci
168180
npm publish --access public
169181
env:
170-
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
182+
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
183+
184+
- name: Login to crates.io
185+
working-directory: ./rust-sdk
186+
run: cargo login ${{ secrets.RUST_TOKEN }}
187+
188+
- name: Publish Rust package
189+
working-directory: ./rust-sdk
190+
run: cargo publish

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,4 +29,5 @@ dist/
2929
go_server_sdk.egg-info/
3030
pyproject.toml
3131

32-
target
32+
target
33+
*.ps1

go-sdk/worker/call.go

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,12 @@
22
package worker
33

44
import (
5+
"crypto/rand"
56
"encoding/json"
67
"errors"
78
"fmt"
8-
"math/rand"
9+
"math/big"
910
"reflect"
10-
"time"
1111

1212
"github.com/go-enols/go-server/go-sdk/scheduler"
1313
)
@@ -31,7 +31,11 @@ func Call(host, method string, params, out interface{}, encryptionKey ...string)
3131
// 如果提供了加密密钥,使用加密方式调用
3232
if len(encryptionKey) > 0 && encryptionKey[0] != "" {
3333
// 生成随机盐值
34-
salt := rand.New(rand.NewSource(time.Now().UnixNano())).Intn(999999) + 100000 // 生成6位随机数
34+
saltBig, err := rand.Int(rand.Reader, big.NewInt(900000))
35+
if err != nil {
36+
return fmt.Errorf("生成随机盐值失败: %v", err)
37+
}
38+
salt := int(saltBig.Int64()) + 100000 // 生成6位随机数
3539
res, err := client.ExecuteEncrypted(method, encryptionKey[0], salt, params)
3640
if err != nil {
3741
return err

scheduler.go

Lines changed: 37 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ const (
2929
TaskExecutionFailedMsg = "Task execution failed"
3030
WorkerTimeoutMsg = "Worker timeout"
3131
WorkerDisconnectedMsg = "Worker disconnected"
32+
ServiceUnavailableMsg = "服务不可用"
3233
)
3334

3435
//go:embed index.html
@@ -189,14 +190,38 @@ func (s *Scheduler) cleanupWorkerTasks(worker *Worker, errorMsg string) {
189190
s.mu.Unlock()
190191
}
191192

193+
// selectWorker 选择可用的Worker来执行指定方法
194+
func (s *Scheduler) selectWorker(method string) *Worker {
195+
var selectedWorker *Worker
196+
minCount := math.MaxInt
197+
198+
s.workers.Range(func(key, value interface{}) bool {
199+
worker := value.(*Worker)
200+
lastPingNano := atomic.LoadInt64(&worker.LastPing)
201+
lastPing := time.Unix(0, lastPingNano)
202+
if time.Since(lastPing) > 60*time.Second {
203+
return true
204+
}
205+
206+
for _, workerMethod := range worker.Methods {
207+
if workerMethod.Name == method {
208+
workerCount := atomic.LoadInt64(&worker.Count)
209+
if workerCount < int64(minCount) {
210+
selectedWorker = worker
211+
minCount = int(workerCount)
212+
}
213+
break
214+
}
215+
}
216+
return true
217+
})
218+
219+
return selectedWorker
220+
}
221+
192222
func (s *Scheduler) handleWorkerMessages(worker *Worker, conn *websocket.Conn) {
193223
for {
194-
var msg struct {
195-
Type string `json:"type"`
196-
TaskID string `json:"taskId"`
197-
Result json.RawMessage `json:"result"`
198-
Error string `json:"error"`
199-
}
224+
var msg TaskResultMessage
200225
if err := conn.ReadJSON(&msg); err != nil {
201226
s.cleanupWorkerTasks(worker, WorkerDisconnectedMsg)
202227
log.Printf("Worker %s disconnected: %v", worker.ID, err)
@@ -207,17 +232,12 @@ func (s *Scheduler) handleWorkerMessages(worker *Worker, conn *websocket.Conn) {
207232
case "pong":
208233
atomic.StoreInt64(&worker.LastPing, time.Now().UnixNano())
209234
case "result":
210-
s.processTaskResult(msg)
235+
s.processTaskResult(&msg)
211236
}
212237
}
213238
}
214239

215-
func (s *Scheduler) processTaskResult(msg struct {
216-
Type string `json:"type"`
217-
TaskID string `json:"taskId"`
218-
Result json.RawMessage `json:"result"`
219-
Error string `json:"error"`
220-
}) {
240+
func (s *Scheduler) processTaskResult(msg *TaskResultMessage) {
221241
s.mu.Lock()
222242
defer s.mu.Unlock()
223243

@@ -273,33 +293,11 @@ func (s *Scheduler) handleEncryptedExecute(w http.ResponseWriter, r *http.Reques
273293
s.encryptedTasks[encryptedTask.ID] = encryptedTask
274294

275295
// 选择可用的Worker
276-
var selectedWorker *Worker
277-
minCount := math.MaxInt
278-
279-
s.workers.Range(func(key, value interface{}) bool {
280-
worker := value.(*Worker)
281-
lastPingNano := atomic.LoadInt64(&worker.LastPing)
282-
lastPing := time.Unix(0, lastPingNano)
283-
if time.Since(lastPing) > 60*time.Second {
284-
return true
285-
}
286-
287-
for _, method := range worker.Methods {
288-
if method.Name == req.Method {
289-
workerCount := atomic.LoadInt64(&worker.Count)
290-
if workerCount < int64(minCount) {
291-
selectedWorker = worker
292-
minCount = int(workerCount)
293-
}
294-
break
295-
}
296-
}
297-
return true
298-
})
296+
selectedWorker := s.selectWorker(req.Method)
299297

300298
if selectedWorker == nil {
301299
encryptedTask.Status = TaskStatusError
302-
encryptedTask.Result = "服务不可用"
300+
encryptedTask.Result = ServiceUnavailableMsg
303301
s.mu.Unlock()
304302
} else {
305303
atomic.AddInt64(&selectedWorker.Count, 1)
@@ -363,36 +361,11 @@ func (s *Scheduler) handleExecute(w http.ResponseWriter, r *http.Request) {
363361
s.tasks.Store(task.ID, task)
364362

365363
// 在同一个锁内完成worker选择和状态更新,避免竞态条件
366-
var selectedWorker *Worker
367-
minCount := math.MaxInt
368-
369-
// 查找可用Worker并验证其连接状态
370-
s.workers.Range(func(key, value interface{}) bool {
371-
worker := value.(*Worker)
372-
// 使用原子操作检查worker连接是否仍然有效
373-
lastPingNano := atomic.LoadInt64(&worker.LastPing)
374-
lastPing := time.Unix(0, lastPingNano)
375-
if time.Since(lastPing) > 60*time.Second {
376-
return true // 跳过可能已断线的worker
377-
}
378-
379-
for _, method := range worker.Methods {
380-
if method.Name == req.Method {
381-
// 使用原子操作读取计数
382-
workerCount := atomic.LoadInt64(&worker.Count)
383-
if workerCount < int64(minCount) {
384-
selectedWorker = worker
385-
minCount = int(workerCount)
386-
}
387-
break // 找到匹配方法就跳出内层循环
388-
}
389-
}
390-
return true
391-
})
364+
selectedWorker := s.selectWorker(req.Method)
392365

393366
if selectedWorker == nil {
394367
task.Status = TaskStatusError
395-
task.Result = "服务不可用"
368+
task.Result = ServiceUnavailableMsg
396369
s.mu.Unlock()
397370
} else {
398371
// 使用原子操作增加计数

types.go

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -17,27 +17,27 @@ type Task struct {
1717
Method string
1818
Params json.RawMessage
1919
Result any
20-
Status TaskStatus // "pending", "processing", "done", "error"
2120
Worker *Worker
2221
Created time.Time
22+
Status TaskStatus // "pending", "processing", "done", "error"
2323
}
2424

2525
type Worker struct {
26-
ID string
2726
Conn *websocket.Conn
2827
Methods []MethodInfo
28+
ConnMu sync.Mutex // 保护websocket连接的并发写入
2929
LastPing int64 // 使用原子操作,存储Unix纳秒时间戳
3030
Count int64 // 使用原子操作
31-
ConnMu sync.Mutex // 保护websocket连接的并发写入
31+
ID string
3232
IP string // Worker的IP地址
3333
Group string // Worker的分组
3434
}
3535

3636
type WorkerInfo struct {
37-
ID string `json:"id"`
3837
Methods []MethodInfo `json:"methods"`
3938
LastPing time.Time `json:"lastPing"`
4039
Count int64 `json:"count"`
40+
ID string `json:"id"`
4141
IP string `json:"ip"`
4242
Group string `json:"group"`
4343
}
@@ -57,13 +57,21 @@ type EncryptedRequest struct {
5757

5858
// EncryptedTask 端到端加密任务结构(调度器只做中转)
5959
type EncryptedTask struct {
60-
ID string
61-
Key string // 用户加盐后的密钥(原封不动传递)
62-
Method string // 方法名(明文,用于路由)
63-
Params string // 加密后的参数(原封不动传递)
64-
Crypto string // 加盐数据(原封不动传递)
65-
Result any
66-
Status TaskStatus
67-
Worker *Worker
68-
Created time.Time
60+
Result interface{} `json:"result"`
61+
Worker *Worker `json:"-"`
62+
Created time.Time `json:"created"`
63+
ID string `json:"id"`
64+
Key string `json:"key"`
65+
Method string `json:"method"`
66+
Params string `json:"params"`
67+
Crypto string `json:"crypto"`
68+
Status TaskStatus `json:"status"`
69+
}
70+
71+
// TaskResultMessage represents the message structure for task results
72+
type TaskResultMessage struct {
73+
Type string `json:"type"`
74+
TaskID string `json:"taskId"`
75+
Error string `json:"error"`
76+
Result json.RawMessage `json:"result"`
6977
}

0 commit comments

Comments
 (0)