Trong vài tháng qua, tôi và đồng nghiệp đã xây dựng thành công hệ thống phía máy chủ để gửi thông báo đẩy tới thiết bị iPhone. Về cơ bản, người dùng đăng ký các thông báo này thông qua một webservice RESTful (Spray-Server, gần đây được cập nhật để sử dụng Spray-can làm lớp HTTP) và logic lên lịch một hoặc nhiều thư để gửi đi trong tương lai bằng cách sử dụng công cụ lên lịch của Akka.Dịch vụ web dựa trên diễn viên - Cách thực hiện đúng cách?
Hệ thống này, như chúng ta đã xây dựng, chỉ hoạt động: có thể xử lý hàng trăm, thậm chí hàng nghìn yêu cầu HTTP một giây và có thể gửi thông báo với tốc độ 23.000 mỗi giây - thậm chí có thể nhiều hơn , thêm nhiều người gửi thông báo cho người gửi (và do đó có nhiều kết nối hơn với Apple) và có thể có một số tối ưu hóa được thực hiện trong thư viện Java mà chúng tôi sử dụng (java-apns).
Câu hỏi này là về cách thực hiện đúng (tm). Đồng nghiệp của tôi, hiểu biết nhiều hơn về Scala và các hệ thống dựa trên diễn viên nói chung, lưu ý cách ứng dụng không phải là hệ thống dựa trên diễn viên 'thuần khiết' - và anh ta đúng. Những gì tôi đang tự hỏi bây giờ là làm thế nào để làm điều đó đúng.
Hiện tại, chúng tôi có một diễn viên Spray HttpService
duy nhất, không được phân lớp, được khởi tạo với một tập hợp các chỉ thị phác thảo logic dịch vụ HTTP của chúng tôi. Hiện nay, rất nhiều đơn giản, chúng ta có chỉ thị như thế này:
post {
content(as[SomeBusinessObject]) { businessObject => request =>
// store the business object in a MongoDB back-end and wait for the ID to be
// returned; we want to send this back to the user.
val businessObjectId = persister !! new PersistSchedule(businessObject)
request.complete("/businessObject/%s".format(businessObjectId))
}
}
Bây giờ, nếu tôi có được quyền này, 'chờ đợi một câu trả lời' từ một diễn viên là một không-không trong chương trình diễn dựa trên (cộng với! ! không được chấp nhận). Điều tôi tin là cách 'đúng' để thực hiện việc này là chuyển đối tượng request
cho diễn viên persister
trong một tin nhắn và gọi cho số request.complete
ngay khi nhận được ID được tạo từ phía sau.
Tôi đã viết lại một trong các tuyến đường trong ứng dụng của mình để thực hiện điều này; trong thông báo được gửi đến tác nhân, đối tượng/tham chiếu yêu cầu cũng được gửi. Điều này dường như làm việc như nó là nghĩa vụ phải:
content(as[SomeBusinessObject]) { businessObject => request =>
persister ! new PersistSchedule(request, businessObject)
}
mối quan tâm chính của tôi ở đây là chúng ta dường như vượt qua các đối tượng request
đến 'logic kinh doanh', trong trường hợp này persister. Hiện tại, persister có trách nhiệm bổ sung, tức là gọi số request.complete
và hiểu biết về hệ thống mà nó chạy, nghĩa là nó là một phần của dịch vụ web.
Cách chính xác để xử lý tình huống như thế này là gì, sao cho diễn viên này trở nên không biết nó là một phần của dịch vụ http và không cần biết cách tạo ID đã tạo?
Tôi nghĩ rằng yêu cầu vẫn nên được chuyển cho diễn viên persister, nhưng thay vì diễn viên persister gọi request.complete, nó sẽ gửi một thông báo lại cho diễn viên HttpService (một thông báo SchedulePersisted(request, businessObjectId)
), chỉ cần gọi request.complete("/businessObject/%s".format(businessObjectId))
. Về cơ bản:
def receive = {
case SchedulePersisted(request, businessObjectId) =>
request.complete("/businessObject/%s".format(businessObjectId))
}
val directives = post {
content(as[SomeBusinessObject]) { businessObject => request =>
persister ! new PersistSchedule(request, businessObject)
}
}
Tôi có đi đúng hướng với phương pháp này không?
Một câu hỏi cụ thể nhỏ hơn spray-server
, có thể phân lớp HttpService
và ghi đè phương thức nhận hoặc tôi sẽ chia nhỏ mọi thứ theo cách đó?(Tôi không có đầu mối về các diễn viên lớp phụ, hoặc cách chuyển các thông điệp không được công nhận cho diễn viên 'phụ huynh')
Câu hỏi cuối cùng, được chuyển qua các thông điệp diễn viên có thể đi qua toàn bộ ứng dụng một cách tiếp cận ổn hoặc có cách nào tốt hơn để 'nhớ' yêu cầu nào sẽ được gửi phản hồi sau khi gửi yêu cầu thông qua ứng dụng?