3

Web サービスを呼び出すための Play 2.0 Scala docを見ると、慣用的なアプローチは Scala の非同期メカニズムを使用して Web サービスを呼び出すことです。たとえば、S3 から画像をダウンロードし、Facebook や Twitter (restfb と twitter4j) にアップロードするために Java ライブラリを使用している場合、これはリソース (どのリソース?) の非常に非効率的な使用になりますか、それとも大きな違いはありませんか? (またはまったく違いはありません)?

それが違いを生む場合、次の非同期のようなものを作成するにはどうすればよいですか? 簡単な方法はありますか、それともライブラリを最初から作成する必要がありますか?

この議論で重要な場合、これはherokuで実行されることに注意してください。

def tweetJpeg = Action(parse.urlFormEncoded) { request =>
  val form = request.body
  val folder = form("folder").head
  val mediaType = form("type").head
  val photo = form("photo").head
  val path = folder + "/" + mediaType + "/" + photo
  val config = Play.current.configuration;
  val awsAccessKey = config.getString("awsAccessKey").get
  val awsSecretKey = config.getString("awsSecretKey").get
  val awsBucket = config.getString("awsBucket").get
  val awsCred = new BasicAWSCredentials(awsAccessKey, awsSecretKey)
  val amazonS3Client = new AmazonS3Client(awsCred)
  val obj = amazonS3Client.getObject(awsBucket, path)
  val stream = obj.getObjectContent()    

  val twitterKey = config.getString("twitterKey").get
  val twitterSecret = config.getString("twitterSecret").get
  val token = form("token").head
  val secret = form("secret").head
  val tweet = form("tweet").head
  val cb = new ConfigurationBuilder();
  cb.setDebugEnabled(true)
    .setOAuthConsumerKey(twitterKey)
    .setOAuthConsumerSecret(twitterSecret)
    .setOAuthAccessToken(token)
    .setOAuthAccessTokenSecret(secret)
  val tf = new TwitterFactory(cb.build())
  val twitter = tf.getInstance()
  val status = new StatusUpdate(tweet)
  status.media(photo, stream)
  val twitResp = twitter.updateStatus(status)

  Logger.info("Tweeted " + twitResp.getText())
  Ok("Tweeted " + twitResp.getText())
}

def facebookJpeg = Action(parse.urlFormEncoded) { request =>
  val form = request.body
  val folder = form("folder").head
  val mediaType = form("type").head
  val photo = form("photo").head
  val path = folder + "/" + mediaType + "/" + photo
  val config = Play.current.configuration;
  val awsAccessKey = config.getString("awsAccessKey").get
  val awsSecretKey = config.getString("awsSecretKey").get
  val awsBucket = config.getString("awsBucket").get
  val awsCred = new BasicAWSCredentials(awsAccessKey, awsSecretKey)
  val amazonS3Client = new AmazonS3Client(awsCred)
  val obj = amazonS3Client.getObject(awsBucket, path)
  val stream = obj.getObjectContent()

  val token = form("token").head
  val msg = form("msg").head
  val facebookClient = new DefaultFacebookClient(token)
  val fbClass = classOf[FacebookType]
  val param = com.restfb.Parameter.`with`("message", msg)
  val attachment = com.restfb.BinaryAttachment`with`(photo + ".png", stream)
  val fbResp = facebookClient.publish("me/photos", fbClass, attachment, param)

  Logger.info("Posted " + fbResp.toString())
  Ok("Posted " + fbResp.toString())
}

私の推測の試み:

  1. はい、非同期で行う方が良いです。すべてを同期的に行うと、スレッドが拘束されます。スレッドはメモリを大量に消費するため、サーバーは非常に多くしか使用できません。待機しているものが多いほど、サーバーが応答できるリクエストは少なくなります。
  2. いいえ、それは大きな問題ではありません。node.js (および Rails? Django?) では、スレッドが 1 つしかなく、Web サーバー全体がブロックされるため、これは大きな問題です。JVM サーバーはマルチスレッド化されているため、引き続き新しい要求を処理できます。
  3. 後で全体を簡単にラップしたり、より細かく実行したりできますが、同じメソッドを呼び出しているため、実際には何も得られません。つまり、あるスレッドから別のスレッドへの待機をシフトしているだけです。
  4. これらの Java ライブラリが非同期メソッドを提供している場合は、将来それらをラップして、非同期の真の利点を得ることができます<-どうすればよいですか? . そうでなければ、あなたはゼロから書くことを見ています。
  5. heroku での実行が重要かどうかはよくわかりません。1つのdyno == 1つの同時リクエストですか?
4

1 に答える 1

1

これらのリクエストは、主に次の 2 つの理由から非同期で行うのが最善だと思います。

  • 高遅延 (ネットワーク呼び出し)
  • 失敗

Play では、Akka アクターを使用してアクションを作成し、これら 2 つの問題に対処する優れた方法を提供する必要があります。問題の同期コードは、Web サーバーをブロックすることです。したがって、他のリクエストには使用できません。ここでは、Web サーバーとは関係のない他のスレッドで待機させます。

次のようなことができます。

// you will have to write the TwitterActor
val twitterActor = Akka.system.actorOf(Props[TwitterActor], name = "twitter-actor")

def tweetJpeg = Action(parse.urlFormEncoded) { request =>
    val futureMessage = (twitterActor ? request.body).map {
         // Do something with the response from the actor
         case ... => ...
     }
     async {
         futureMessage.map( message =>
             ok("Tweeted " + message)
         )
     }
}

アクターはボディを受け取り、サービスの応答を返します。さらに、Akka を使用すると、複数のアクターを利用できるようにプロセスを調整したり、サーキット ブレーカーを使用したりできます。

さらに進むには: http://doc.akka.io/docs/akka/2.1.2/scala/actors.html

Ps: Heroku でプレイしたことがないので、ダイナモ単体の影響はわかりません。

于 2013-05-03T15:52:30.737 に答える