0
votes

EDIT: Problem wasn't related to Timer or HttpServer, it was dart.io sleep function pausing everything. It is clearly described in documentation, my bad.

//

I have weird problem with HttpClient working in server code. I call

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

from Timer object and it never reach print step. It is almost copy and paste code from previous version, which wasn't called from Timer but from HttpRequest. Working code is in my question [here][1]. It fails on the long line, I suspect that it is a last Future it never reach (HttpClientResponseBody).

Timer object is created like this (just test code):

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");

//edit: okay, here is the source, it might be some trivial problem..which I can't figure out for two days :-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();
}
1
Your code fragments seem a bit disconnected. Can you create a minimal code example that allows to reproduce the problem? You write getUrl from Timer doesn't work, but you call hit() from Timer. I assume you forgot some return or similar simple oversight, but it's hard to tell form your code. - Günter Zöchbauer
The updated code is much better, but you should have stripped it down to a minimum that allows to reproduce the problem. Do you think handleMap and send2Slack are related to your problem? Where is the definition of sleep. You really should try to reduce your code so that the minimum amount of code necessary to reproduce your problem is left. Most of the time this alone reveals the cause of the problem. - Günter Zöchbauer
okay, working on it, seems that sleep freeze all processes and it caused freeze of the request in the middle :) - Adam Sobotka
Can you add the implementation of sleep() to your question? sleep seems weird. I think you try something that doesn't work well in Dart. Dart doesn't provide something like sleep itself because it doesn't fit well in the async programming model. I guess you'll need another approach. If I can have a look at your code I might be able to make a suggestion. - Günter Zöchbauer

1 Answers

0
votes

I created similar code but I can't reproduce your problem.
So basically this does work when called from a 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)); 
      });
}

You don't need to use a Completer. Completer are for more complicated used cases where for example one method returns a Completer and for example an eventHandler completes it.

You just have to ensure that you return a Future everywhere. then always returns a Future. The value of the returned Future is the value returned inside then.