云代码 - 在afterSave中的saveAll调用期间“执行超时”

时间:2014-07-02 12:46:26

标签: timeout parse-platform request-timed-out

情况

  • 我有一个消息传递Android应用程序,提供以下功能
    • 向所选收件人发送邮件直接邮件
    • 创建公告,表明所有使用该应用的用户都会收到(作者除外)
    • 每个用户在手机上看到他收到的邮件列表
    • 每条消息都是未读,已读或已删除
  • 我使用Parse.com作为后端

当前实施

在Android客户端

  1. 当有新消息时,会创建MessageRequest类的新messageRequest
  2. 如果消息应该是直接消息,则messageRequest的类型为0,否则键入1
  3. 如果邮件是直接邮件,则邮件存储在messageRequest对象
  4. messageRequest对象存储到parse.com
  5. 在parse.com后端

    在MessageRequest的afterSave中,检查消息是直接消息还是公共消息并基于此消息

    • 在直接消息的情况下 - 创建并保存Message类的一个新消息对象
    • 如果是公告 - 对于除作者以外的每个用户,都会创建一个新的消息对象并将其添加到消息列表中,然后保存列表

    在这两种情况下,内容,类型等数据都会从messageRequest对象复制到新创建的消息对象中。

    为每个用户创建单独邮件的原因是每个用户都可以将其置于其他状态(未读,已读,已删除)。

    表示未读,已读,已删除状态的状态列是为消息对象设置的(未读)。

    问题

    当我在MessageRequest的ParseObject.saveAll中调用afterSave方法时,我得到执行超时 - 请求超时错误

    我认为原因是请求必须完成的时间有一些限制 在云代码中。就我而言,我正在为1个MessageRequest创建大约100条消息

    这对我来说似乎并不多,但也许我错了。

    源代码

    var generateAnnouncement = function(messageRequest, recipients) {
    
        var messageList = [];
    
        for (var i = 0; i < recipients.length; i++) {
            var msg = new Message();
            msg.set("type", 1);
            msg.set("author", messageRequest.get("author"));
            msg.set("content", messageRequest.get("content"));
            msg.set("recipient", recipients[i]);
            msg.set("status", 0)
    
            messageList.push(msg);
        }
    
        Parse.Object.saveAll(messageList).then(function(list) {
        }, function(error) {
            console.error(error.message);
        });
    
    }
    
    Parse.Cloud.afterSave("MessageRequest", function(request) {
        var mr = request.object;
        var type = mr.get("type");
    
        if (type == 0) {
            generateDirectMessage(mr);
        } else {
            var query = new Parse.Query(Parse.User);
            query.notEqualTo("objectId", mr.get("author").id);
            query.find().then(function(allUsersExceptAuthor) {
                generateAnnouncement(mr, allUsersExceptAuthor);
            }, function(error) {
                console.error(error.message);
            });
        }
    });
    

    您如何建议解决此问题?

    其他想法

    • 我唯一的另一个想法是如何解决这个问题,只有一个Message对象,以及两个名为例如已查看并已删除其中包含已查看邮件或已删除邮件的用户列表。
    • 在这种情况下,我不太确定查询的效果

    • 另外,我知道,很多人都认为为什么他不使用表来分割MessageRequest(在这种情况下实际上可能称为Message)和User?之间的M:N关系? / EM>

    • 我的回答是我有这个解决方案,但在Android代码中使用它更难,更多指针,更多包含在查询中等。
    • 此外,无论如何,我必须为on parse.com后端的每个用户创建相同数量的对象,因此我认为执行超时的问题最终会是相同的

    更新 - 代表用户“收件箱”

    的模型

    Inbox mockup

    在“收件箱”中,用户可以看到直接消息和公告。它们按时间顺序排序。

    更新#2 - 使用数组来识别查看者和标记为已删除的人

    • 我只有一个Message个对象,通过类型I识别它是直接还是公开
    • 添加了两个阵列列
      • viewedBy - 包含已查看邮件的用户
      • deletedFor - 包含将邮件标记为已删除的用户

    然后我对当前登录用户未删除的所有邮件的查询如下所示

    //direct messages for me
    ParseQuery<Message> queryDirect = ParseQuery.getQuery(Message.class);
    queryDirect.whereEqualTo("type", 0);
    queryDirect.whereEqualTo("recipient", ParseUser.getCurrentUser());
    
    //public announcements
    ParseQuery<Message> queryAnnouncements = ParseQuery.getQuery(Message.class);
    queryAnnouncements.whereEqualTo("type", 1);
    
    //I want both direct and public
    List<ParseQuery<Message>> queries = new ArrayList<ParseQuery<Message>>();
    queries.add(queryDirect);
    queries.add(queryAnnouncements);
    
    ParseQuery<Message> queryMessages = ParseQuery.or(queries);
    //... but only those which I haven't deleted for myself
    queryMessages.whereNotEqualTo("deletedFor", ParseUser.getCurrentUser());
    //puting them in correct order
    queryMessages.addDescendingOrder("createdAt");
    //and attaching the author ParseUser object (to get e.g. his name or URL to photo)
    queryMessages.include("author");
    queryMessages.findInBackground(new FindCallback<Message>() {/*DO SOMETHING HERE*/});
    

1 个答案:

答案 0 :(得分:1)

我建议更改您的架构以更好地支持公共消息。

您应该拥有公共消息的单个副本,因为不会更改消息本身。

如果除了“未读”之外的其他任何用户,您应该只保存每个用户的状态。这将是另一张表。

当MessageRequest带有类型1时,创建一个新的PublicMessage,不要创建任何状态行,因为每个人都将使用默认状态“unread”。这使您的afterSave处理程序干净利落,因为它始终只创建一个新对象,MessagePublicMessage

当每个用户阅读或删除邮件时,请为该用户创建具有正确状态的新PublicMessageStatus行。

向用户显示公开消息时,您将执行两个查询:

  1. 查询PublicMessage,可能有一些日期范围
  2. 使用第一个查询的克隆,使用与PublicMessageStatus匹配当前用户和user约束的过滤器matchesQuery('publicMessage', publicMessageQuery)查询Message
  3. 客户端您需要将两者合并以隐藏/删除状态为“已删除”的那些,并相应地标记状态为“已读”的那些。

    根据反馈进行更新

    您可以选择将单个MessageStatus类用于公共/私人消息,并选择Message.recipient类来处理状态。

    Public vs Private将基于// JavaScript sample since you haven't specified a language // assumes Underscore library available var Message = Parse.Object.extend('Message'); var MessageStatus = Parse.Object.extend('MessageStatus'); var publicMessageQuery = new Parse.Query(Message); publicMessageQuery.doesNotExist('recipient'); publicMessageQuery.notEqualTo('author', currentUser); var privateMessageQuery = new Parse.Query(Message); privateMessageQuery.equalTo('recipient', currentUser); var messagesQuery = new Parse.Query.or(publicMessageQuery, privateMessageQuery); messagesQuery.descending('createdAt'); // set any other filters to apply to both queries var messages = []; messageQuery.find().then(function(results) { messages = _(results).map(function (message) { return { message: message, status: 'unread', messageId: message.objectId }; }); var statusQuery = new Parse.Query(MessageStatus); statusQuery.containedIn('message', results); statusQuery.equalTo('user', currentUser); // process status in order so last applies statusQuery.ascending('createdAt'); return }).then(function(results) { _(results).each(function (messageStatus) { var messageId = messageStatus.get('message').objectId; _(messages).findWhere({ messageId: messageId }).status = messageStatus.get('status'); }); }); // optionally filter messages that are deleted messages = _(messages).filter(function(message) { return message.status !== 'deleted'; }); // feed messages array to UI... 是否为空。

    获取当前用户的所有消息:

    {{1}}