踩到的坑
首先說一句老話:Windows就是善於製造別的作業系統中不存在的問題。
本來我這裡有一個提供檔案服務的東西是基於Python開發的,在Linux上執行的還行。但是最近因為需要部署到Windows上,就碰到了一個在別的平臺不存在的問題:常用的WSGI伺服器都不支援Windows或者支援得不好。而如果不用WSGI伺服器來跑的話,併發處理又不行。
找了半天也沒有找到什麼像樣的解決辦法,只好用Go改寫了,但是因為還是有很多後續處理不方便用Go改寫(因為沒有相關的庫可用),所以折衷方案是Web端用Go,後端繼續用Python,二者之間通過訊息佇列解耦。因為正好伺服器上有一個給其它Java應用使用的ActiveMQ,就拿來用了。
本來改寫還挺順利的,但是結果踩到一個坑:Go的Stomp庫文件不夠詳細,所以拿它的例子程式碼寫了個DEMO結果調不通。搜了半天也不知道問題在哪裡。只能自己看原始碼研究,還好最後還是搞通了。
一個DEMO
下面的DEMO裡,Go版和Python分別訂閱了一個佇列,然後Go向Python的佇列發一條訊息,Python收到後再向Go的佇列傳送一條訊息。
Golang
package main
import (
"time"
"github.com/go-stomp/stomp"
)
var config map[string]interface{}
var stop = make(chan bool)
var options []func(*stomp.Conn) error = []func(*stomp.Conn) error{
stomp.ConnOpt.Host("demo"),
stomp.ConnOpt.HeartBeat(360*time.Second, 360*time.Second),
stomp.ConnOpt.HeartBeatError(360*time.Second),
}
func recvMessages(subscribed chan bool) {
conn, err := stomp.Dial("tcp", config["AMQ_SERVER"].(string), options...)
if err != nil {
println("Cannot connect to server: ", err.Error())
subscribed <- false
return
}
defer func() {
conn.Disconnect()
println("Go disconnected")
stop <- true
}()
sub, err := conn.Subscribe(config["AMQ_DEST_RESP"].(string), stomp.AckAuto)
if err != nil {
println("Cannot subscribe: ", config["AMQ_DEST_RESP"].(string), err.Error())
subscribed <- false
return
}
println("Go subscribed!")
subscribed <- true
close(subscribed)
msg := <- sub.C
println("Go received: ", string(msg.Body))
}
func sendMessage(content string) {
conn, err := stomp.Dial("tcp", config["AMQ_SERVER"].(string), options...)
if err != nil {
println("Cannot connect to server: ", err.Error())
return
}
defer func() {
conn.Disconnect()
stop <- true
}()
err = conn.Send(config["AMQ_DEST_REQ"].(string), "text/plain", []byte(content))
if err != nil {
println("Send fail: ", err.Error())
return
}
println("Go sent!")
}
func main() {
config = map[string]interface{} {
"AMQ_SERVER": "localhost:61613",
"AMQ_DEST_REQ": "demoRequest",
"AMQ_DEST_RESP": "demoResponse",
}
subscribed := make(chan bool)
go recvMessages(subscribed)
sub_res := <-subscribed
if sub_res {
println("Go Sending...")
go sendMessage("Hello world")
}
<-stop
<-stop
}
複製程式碼
Python
# -*- coding:UTF-8 -*-
import atexit
import time
import logging
import stomp
__author__ = 'raptor'
__doc__ = """
"""
logger = logging.getLogger(__name__)
class AMQListener(stomp.ConnectionListener):
def __init__(self, amq):
super(AMQListener, self).__init__()
self.amq = amq
def on_error(self, headers, message):
logger.error('Python received an error "%s"' % message)
def on_message(self, headers, message):
logger.info("Python received: %s" % message)
self.amq.send("Hello ActiveMQ")
self.amq.term = True
class AMQConnection(object):
HOST = "localhost"
PORT = 61613
DEST_REQ = "demoRequest"
DEST_RESP = "demoResponse"
def __init__(self):
self.conn = stomp.Connection([(self.HOST, self.PORT)])
self.conn.set_listener(self.DEST_REQ, AMQListener(self))
self.conn.start()
self.conn.connect()
self.conn.subscribe(self.DEST_REQ, '1', 'auto')
logger.info("Python subscribed!")
atexit.register(self.close)
self.term = False
def run_forever(self):
while not self.term:
time.sleep(5)
def send(self, content):
logger.info("Python sending...")
self.conn.send(self.DEST_RESP, body=content)
logger.info("Python sent!")
def close(self):
self.conn.disconnect()
logger.info("Python disconnected")
if __name__ == "__main__":
logging.basicConfig(level=logging.INFO)
amq = AMQConnection()
amq.run_forever()
複製程式碼