2016-12-05 22 views
0

私はソートオブリアクティブゴーランの実装を実装しようとしていました。私はオブザーバーの配列を持っています。彼らはちょうどチャンネルの束です。すべてがパッケージにカプセル化されており、他のコードは購読と購読解除が可能です。これまで注文が作成されると、変更がプッシュされます。しかし、私は方法でチャネル受信を登録するのに失敗しました。goでメソッドによってチャネルに送信された値は外部で受信できません

package rxOrder 

import (
    "fmt" 
    "time" 

    "errors" 

    "gopkg.in/mgo.v2/bson" 
) 

// Order This is the sample data structure 
type Order struct { 
    id  bson.ObjectId 
    moldID bson.ObjectId 
    bomID  bson.ObjectId 
    deviceID bson.ObjectId 
    userIds []bson.ObjectId 
    name  string 
    orderType string // withOrder, noOrder, makeUp, test 
    startTime time.Time 
    deadline time.Time 
    volume int32 
} 

// OrderMutation This is the struct for sending 
// mutations to observers 
type OrderMutation struct { 
    order Order 
    action string 
} 

// RxOrder This is the node for reactive Order 
// management 
type RxOrder struct { 
    orders []Order 
    observers map[string]chan OrderMutation 
} 

// init This method initialize RxOrder, including 
// orders slice and subscriber map, user cannot 
// initialize a RxOrder object more than once 
func (rx *RxOrder) init() error { 
    if len(rx.orders) == 0 && len(rx.observers) == 0 { 
     rx.orders = make([]Order, 1) 
     rx.observers = make(map[string]chan OrderMutation) 
     return nil 
    } 

    return errors.New("Cannot reinitialize orders") 
} 

// subscribe, add observer to list 
func (rx *RxOrder) subscribe(key string, ch chan OrderMutation) error { 
    if _, ok := rx.observers[key]; ok { 
     return errors.New("Observer already existed") 
    } 

    rx.observers[key] = ch 

    return nil 
} 

// unsubscribe, delete observer from list 
func (rx *RxOrder) unsubscribe(key string) error { 
    if _, ok := rx.observers[key]; !ok { 
     return errors.New("Observer does not exist") 
    } 

    delete(rx.observers, key) 

    return nil 
} 

// createOrder The method for creating an order 
func (rx *RxOrder) createOrder(order Order) error { 

    if !order.id.Valid() { 
     return errors.New("Invalid order id") 
    } 

    if !order.bomID.Valid() { 
     return errors.New("Invalid bom id") 
    } 

    if !order.deviceID.Valid() { 
     return errors.New("Invalid device id") 
    } 

    if !order.moldID.Valid() { 
     return errors.New("Invalid mold id") 
    } 

    if len(order.userIds) < 1 { 
     return errors.New("Empty users list") 
    } 

    for index, userID := range order.userIds { 
     if !userID.Valid() { 
      return errors.New(fmt.Sprint("Invalid user id at index: ", index)) 
     } 
    } 

    if len(order.name) < 1 { 
     return errors.New("Empty order name") 
    } 

    if order.orderType != "withOrder" && order.orderType != "noOrder" && order.orderType != "makeUp" && order.orderType != "test" { 
     return errors.New("Wrong order type") 
    } 

    if order.startTime.After(order.deadline) { 
     return errors.New("Deadline cannot come before start time") 
    } 

    if order.volume < 1 { 
     return errors.New("Empty order is not accepted") 
    } 

    rx.orders = append(rx.orders, order) 

    for _, ch := range rx.observers { 
     ch <- OrderMutation{order, "create"} 
    } 

    return nil 
} 
func TestCreateOrder(t *testing.T) { 
    orderManagement := RxOrder{} 

    orderManagement.init() 

    orderManagement.subscribe("123", make(chan OrderMutation)) 
    orderManagement.subscribe("345", make(chan OrderMutation)) 
    orderManagement.subscribe("768", make(chan OrderMutation)) 

    order := Order{} 
    order.id = bson.NewObjectId() 
    order.bomID = bson.NewObjectId() 
    order.deviceID = bson.NewObjectId() 
    order.moldID = bson.NewObjectId() 
    order.name = "iPhone 8+" 
    order.orderType = "withOrder" 
    order.volume = 5 
    order.startTime = time.Now() 
    order.deadline = order.startTime.AddDate(0, 1, 1) 
    order.userIds = make([]bson.ObjectId, 1) 
    order.userIds = append(order.userIds, bson.NewObjectId()) 

    go func(t *testing.T) { 
     fmt.Println(<-orderManagement.observers["123"]) 
    }(t) 

    orderManagement.createOrder(order) 
    //orderManagement.observers["123"] <- OrderMutation{order, "w"} 

    t.Fail() 
} 

私がテストを行う際に、上記のコードは何も出力しませんが、私のコメントを解除行場合:すべてが動作します

orderManagement.observers["123"] <- OrderMutation{order, "w"} 

。メソッド内のチャンネルでは操作できないようです。パッケージでチャネル操作をカプセル化するにはどうすればよいですか?

+3

あなたは絶対にメソッド内のチャンネルで操作できます。最後に実行されるt.Fail()が常に実行されるため、テストは失敗します。条件付きで失敗する必要があります。 –

+0

t.Fail()を介してのみ、テストプリントをコンソールに送ることができます。メソッド経由で送信された値は、受信側で受信側で受信されませんでした。 – Nexus2020

+2

あなたは競合状態にあると思います。テストが終了する前にgoroutineがメッセージを出力するという保証はありません。 –

答えて

0

状況は、次の出力に依存します:

は、あなたがエラーを返すcreateOrderていますか?

createOrderにエラーがある場合、チャネル上にメッセージは送信されませんので、メインのテスト機能が待機することなくその行にコメントすることで終了します。

上記の行を追加すると、メインテスト関数はコルーチンがメッセージを受信して​​出力を出力するまで、チャネル操作を待機します。

createOrderにエラーがない場合、 "123"以外のチャンネルで送信されたメッセージがメインテスト機能を永遠にブロックするため、競合状態になります。

+0

いいえ、エラーがなくても値を受け取っていないことを確認しました。 – Nexus2020

+0

これは常に という致命的なエラーを表示します。すべてのゴルーチンが眠っています - デッドロックです! – Nexus2020

+0

'' '行く ERR:= orderManagement.createOrder(オーダー) 誤る場合= nilを!{ fmt.Println( "orderManagementエラー:"、ERR) } ' '' ERR createOrderをチェックするためにこれを追加し、そして、あなたはここで、いくつかのログを印刷することができます '' '_、CHため を行く:=レンジrx.observers - ' '' – sydnash

0

これを実行した後、すべてが機能します。

go func() { 
    for _, ch: = range rx.observers { 
    ch <-OrderMutation { 
     order, "create" 
    } 
    } 
}() 

// create a goroutine to send message 

    func() { 
     orderManagement.createOrder(order) 
    }() 

    select { 
    case val := <-orderManagement.observers["123"]: 
     fmt.Println(val) 
    } 

// then receive on the outside like this 

解決方法がなくてもすべて動作します。

+0

に役立ちますしかし、私はまだ他のオプション – Nexus2020

関連する問題