2012-07-13 48 views
5

Tôi đang cố gắng hiểu các khái niệm I/O phản ứng của khung công tác Play 2.0. Để có được sự hiểu biết tốt hơn từ đầu, tôi quyết định bỏ qua các trình trợ giúp của khung công tác để xây dựng các loại lặp lại và viết Iteratee tùy chỉnh từ đầu để được sử dụng bởi một số BodyParser để phân tích cú pháp phần thân yêu cầu.Tại sao làm cho lỗi gọi điện thoại hoặc thực hiện trong một Iteratee của BodyParser yêu cầu treo trong Play Framework 2.0?

Bắt đầu với những thông tin có sẵn trong IterateesScalaBodyParser tài liệu và hai bài thuyết trình về vở kịch phản ứng I/O này là những gì tôi đã đưa ra:

import play.api.mvc._ 
import play.api.mvc.Results._ 
import play.api.libs.iteratee.{Iteratee, Input} 
import play.api.libs.concurrent.Promise 
import play.api.libs.iteratee.Input.{El, EOF, Empty} 

01 object Upload extends Controller { 
02 def send = Action(BodyParser(rh => new SomeIteratee)) { request => 
03  Ok("Done") 
04 } 
05 } 
06 
07 case class SomeIteratee(state: Symbol = 'Cont, input: Input[Array[Byte]] = Empty, received: Int = 0) extends Iteratee[Array[Byte], Either[Result, Int]] { 
08 println(state + " " + input + " " + received) 
09 
10 def fold[B](
11  done: (Either[Result, Int], Input[Array[Byte]]) => Promise[B], 
12  cont: (Input[Array[Byte]] => Iteratee[Array[Byte], Either[Result, Int]]) => Promise[B], 
13  error: (String, Input[Array[Byte]]) => Promise[B] 
14 ): Promise[B] = state match { 
15  case 'Done => { println("Done"); done(Right(received), Input.Empty) } 
16  case 'Cont => cont(in => in match { 
17  case in: El[Array[Byte]] => copy(input = in, received = received + in.e.length) 
18  case Empty => copy(input = in) 
19  case EOF => copy(state = 'Done, input = in) 
20  case _ => copy(state = 'Error, input = in) 
21  }) 
22  case _ => { println("Error"); error("Some error.", input) } 
23 } 
24 } 

(Ghi chú: Tất cả những điều này là mới với tôi Vì vậy, xin vui lòng tha thứ nếu một cái gì đó về điều này là tổng số crap.) Iteratee là khá câm, nó chỉ đọc tất cả các khối, tổng hợp số lượng byte nhận được và in ra một số tin nhắn. Mọi thứ hoạt động như mong đợi khi tôi gọi hành động điều khiển với một số dữ liệu - tôi có thể quan sát tất cả các khối được nhận bởi Iteratee và khi tất cả dữ liệu được đọc, nó chuyển sang trạng thái được thực hiện và yêu cầu kết thúc.

Bây giờ tôi bắt đầu để chơi xung quanh với mã vì tôi muốn thấy những hành vi đối với hai trường hợp sau đây:

  • Switching vào lỗi trạng thái trước khi tất cả các đầu vào được đọc.
  • Chuyển sang trạng thái được thực hiện trước khi tất cả đầu vào được đọc và trả lại Result thay vì Int.

Sự hiểu biết của tôi về tài liệu được đề cập ở trên là cả hai có thể thực hiện được nhưng thực tế tôi không thể hiểu hành vi được quan sát. Để kiểm tra trường hợp đầu tiên tôi đã thay đổi dòng 17 của mã trên thành:

17  case in: El[Array[Byte]] => copy(state = if(received + in.e.length > 10000) 'Error else 'Cont, input = in, received = received + in.e.length) 

Vì vậy, tôi vừa thêm điều kiện để chuyển sang trạng thái lỗi nếu nhận được hơn 10000 byte. Kết quả tôi nhận được là:

'Cont Empty 0 
'Cont El([[email protected]) 8192 
'Error El([[email protected]) 16384 
Error 
Error 
Error 
Error 
Error 
Error 
Error 
Error 
Error 
Error 
Error 

Sau đó, yêu cầu treo vĩnh viễn và không bao giờ kết thúc. Kỳ vọng của tôi từ các tài liệu được đề cập ở trên là khi tôi gọi hàm error bên trong fold của Iteratee, quá trình xử lý phải được dừng lại. Những gì đang xảy ra ở đây là phương pháp gấp của Iteratee được gọi nhiều lần sau khi error được gọi - tốt và sau đó yêu cầu bị treo.

Khi tôi chuyển sang trạng thái đã hoàn thành trước khi đọc tất cả đầu vào, hành vi tương tự. Thay đổi dòng 15 để:

15 case 'Done => { println("Done with " + input); done(if (input == EOF) Right(received) else Left(BadRequest), Input.Empty) } 

và dòng 17 để:

17  case in: El[Array[Byte]] => copy(state = if(received + in.e.length > 10000) 'Done else 'Cont, input = in, received = received + in.e.length) 

xuất ra như sau:

'Cont Empty 0 
'Cont El([[email protected]) 8192 
'Done El([[email protected]) 16384 
Done with El([[email protected]) 
Done with El([[email protected]) 
Done with El([[email protected]) 
Done with El([[email protected]) 

và một lần nữa yêu cầu treo mãi mãi.

Câu hỏi chính của tôi là tại sao yêu cầu bị treo trong các trường hợp được đề cập ở trên. Nếu ai đó có thể làm sáng tỏ điều này, tôi sẽ đánh giá cao điều đó!

Trả lời

4

hiểu biết của bạn là hoàn toàn đúng và tôi vừa đẩy một sửa chữa để làm chủ:

https://github.com/playframework/Play20/commit/ef70e641d9114ff8225332bf18b4dd995bd39bcc

cố định cả hai trường hợp cộng với ngoại lệ trong Iteratees.

Sử dụng bản sao đẹp trong trường hợp lớp học để thực hiện một BTT Iteratee.

+0

Cảm ơn bạn đã sửa chữa và các từ loại, sẽ cố gắng sửa chữa càng sớm càng tốt! – lost

0

Mọi thứ phải thay đổi với Play 2.1 - Lời hứa không còn tham số nữa và ví dụ này không còn biên dịch nữa.