【问题标题】:Dart HttpClient.getUrl invoked by Timer without client or http server没有客户端或 http 服务器的 Timer 调用 Dart HttpClient.getUrl
【发布时间】:2014-06-27 07:53:16
【问题描述】:

编辑:问题与 Timer 或 HttpServer 无关,它是 dart.io 睡眠功能暂停一切。文档中清楚地描述了它,我的错。

//

我在 HttpClient 在服务器代码中工作时遇到了奇怪的问题。我打电话给

client.getUrl(Uri.parse(url)).then((HttpClientRequest response) => response.close()).then(HttpBodyHandler.processResponse).then((HttpClientResponseBody body) {
    print(body.response.statusCode);

来自 Timer 对象,它永远不会到达打印步骤。 它几乎是以前版本的复制和粘贴代码,不是从 Timer 调用而是从 HttpRequest 调用的。工作代码在我的问题 [这里][1] 中。 从长远来看它失败了,我怀疑这是它永远无法到达的最后一个 Future (HttpClientResponseBody)。

Timer 对象是这样创建的(只是测试代码):

main() {
  t = new Timer.periodic(new Duration(minutes: period), (Timer t) => hit());

}

void hit() {
  if (new DateTime.now().hour == 17) {
    print("syncing rock");

    loadUrlBody(furl + filter).then((content) {
      print("content loaded");

//编辑: 好的,这是源代码,可能是一些琐碎的问题..我两天都想不通:-D

import 'dart:async';
import 'dart:io';
import 'package:http_server/http_server.dart';
import 'package:slack/slack_io.dart' as slack;

Timer t;
bool check;
final period = 1;
final furl = "https://****.tpondemand.com";
final filter = "somefilter";


main() {
  t = new Timer.periodic(new Duration(minutes: period), (Timer t) => hit());

}

void hit() {
  if (new DateTime.now().hour == 17) {
    print("syncing rock");

    loadUrlBody(furl + filter).then((content) {
      print("content loaded");
      Map parsedMap = content.body;
      handleMap(parsedMap);
    });
    sleep(new Duration(minutes: 60));
  } else {
    print("no time to rock " + new DateTime.now().toString());
    sleep(new Duration(minutes: period * 10));
  }
}

Future loadUrlBody(String url) {
  final c = new Completer();
  HttpClient client = new HttpClient();
  client.addCredentials(Uri.parse("https://****.tpondemand.com/api"), "tprealm", new HttpClientBasicCredentials("user", "password"));
  client.getUrl(Uri.parse(url)).then((HttpClientRequest response) => response.close()).then(HttpBodyHandler.processResponse).then((HttpClientResponseBody body) {
    print(body.response.statusCode);
    c.complete(body);
  });
  return c.future;
}



void send2Slack(String m) {
  slack.Message message = new slack.Message()..text = m;

  slack.token = 'token';
  slack.team = 'team';
  slack.send(message);
}
void handleMap(Map valueMap) {

  final Duration lostInTime = new Duration(days: 30);
  var sb = new StringBuffer();
  sb.write('K o m p o s t \n');

  for (var item in valueMap["Items"]) {
    if (item['CreateDate'] == null) item['CreateDate'] = '/Date(1403167885000+0100)/';
    if (item['ModifyDate'] == null) item['ModifyDate'] = '/Date(1403167885000+0100)/';
    if (item['LastCommentDate'] == null) item['LastCommentDate'] = '/Date(1403167885000+0100)/';

    DateTime moonLanding = new DateTime.fromMillisecondsSinceEpoch(int.parse(item['CreateDate'].substring(6, 19)));
    DateTime modifyLanding = new DateTime.fromMillisecondsSinceEpoch(int.parse(item['ModifyDate'].substring(6, 19)));
    DateTime commentLanding = new DateTime.fromMillisecondsSinceEpoch(int.parse(item['LastCommentDate'].substring(6, 19)));
    DateTime lastChangeLanding = (modifyLanding.isBefore(commentLanding)) ? commentLanding : modifyLanding;
    Duration difference = new DateTime.now().difference(lastChangeLanding);

    if (moonLanding.add(lostInTime).isBefore(new DateTime.now()) && difference.inDays > 4) {
      sb
          ..write('<https://****.tpondemand.com/entity/')
          ..write(item['Id'])
          ..write('|')
          ..write(item['Name'])
          ..write('> last change: ')
          ..write(difference.inDays)
          ..write(' days ago \n');

    }
    ;


  }
  send2Slack(sb.toString());
  print("sent to Slack");
  sb.clear();
}

【问题讨论】:

  • 您的代码片段似乎有点脱节。你能创建一个允许重现问题的最小代码示例吗?你从TimergetUrl 不起作用,但是你从Timer 调用hit()。我假设您忘记了一些 return 或类似的简单疏忽,但很难从您的代码中分辨出来。
  • 更新后的代码要好得多,但您应该将其精简到允许重现问题的最低限度。您认为handleMapsend2Slack 与您的问题有关吗? sleep 的定义在哪里。您确实应该尝试减少代码,以便留下重现问题所需的最少代码量。大多数情况下,仅此一项就可以揭示问题的原因。
  • 好的,正在处理它,似乎睡眠冻结了所有进程,并导致中间的请求冻结:)
  • 您能否将sleep() 的实现添加到您的问题中? sleep 似乎很奇怪。我认为你尝试了一些在 Dart 中效果不佳的东西。 Dart 本身不提供类似sleep 的东西,因为它不适合异步编程模型。我想你需要另一种方法。如果我可以看看你的代码,我可能会提出建议。

标签: dart server-side dart-async


【解决方案1】:

我创建了类似的代码,但无法重现您的问题。
所以基本上这在从Timer 调用时确实有效。

import 'dart:io';
import 'dart:async';
import 'package:http_server/http_server.dart';

Timer t;
final period = 1;

void main(args) {
  t = new Timer.periodic(new Duration(minutes: period), (Timer t) => hit());
}

void hit() {
  loadUrlBody('http://www.google.com')
      .then((HttpClientResponseBody b) => print('hit: ${b.response.statusCode}'));
}

Future loadUrlBody(String url) {
  print('executing');
  HttpClient client = new HttpClient();
  // commented out because I have no server where I can use it
  // HttpClient client = new HttpClient()              
  //    ..addCredentials(Uri.parse("https://****.tpondemand.com/api"), "tprealm", new HttpClientBasicCredentials("user", "password"));
  return client.getUrl(Uri.parse(url))        // <== return is important here
      .then((HttpClientRequest response) => response.close())
      .then(HttpBodyHandler.processResponse)
      .then((HttpClientResponseBody body) {
        print('body: (${new DateTime.now()}) ${body.response.statusCode}');
        return body;                         // <== this value is the value the next 'then' receives. 
// for example x in: loadUrlBody('http://someurl').then(x) => doSomething(x)); 
      });
}

您不需要使用Completer。 Completer 用于更复杂的用例,例如一个方法返回一个 Completer,例如一个 eventHandler 完成它。

您只需要确保在任何地方都返回Futurethen 总是返回 Future。返回的Future的值就是then内部返回的值。

【讨论】:

  • 感谢您简化我的代码,我误解了 Completer 的概念。我的问题与 sleep 函数有关,我认为 Future 是一种线程,但事实并非如此,并且 sleep 暂停了它。
  • Isolate 与 Dart 中的线程最相似。 Future 是关于异步编程的。这意味着当一些代码在等待响应时(例如委托给操作系统的 I/O 操作),其他代码可以被执行。这是一个分时模型。一个隔离中的所有代码都运行在同一个 CPU 内核上。 Future 也可以看作是一个更简单的回调 API。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-10-30
  • 2011-12-06
  • 1970-01-01
相关资源
最近更新 更多