James
Community Champion

@Carter41 

This would require programming, especially since you want to customize the messages.

Let me give some approaches you might take.

You could set up an LTI and add it as a the next module item after "Your Final Reflection". Then, when the LTI is launched, it could send the message to the students -- or even just display it on the screen. I programmed something similar over a decade ago. We have a Canvas student orientation that students must complete before they can get into their real courses. The final assignment there was a quiz that they had to pass with a certain score. The next item was an LTI that let our systems know that they had finished the course and it then moved them into their real courses.

The problem is that not all the students were clicking on the LTI, so I had to move on to a second approach. Ultimately, we dropped the LTI and just went with the second method.

 

The second approach is to use the submissions API to get the list of submissions for an assignment. With the REST API, you can use the list submissions for multiple assignments endpoint. This doesn't allow you to get multiple assignments from multiple courses, but it does allow you to specify either submitted_since or graded_since to get the recent changes rather than downloading all the submissions. You may have to deal with pagination in the requests depending on how often you poll. The default is usually 10 results at a time, but you can specify up to 100 on most things. Specifying the submitted_since query parameter can help limit the number of results returned, which also reduces the chances of needing pagination.

The GraphQL interface can be used to get submission information and is generally faster and you can include information about the student. But the submission filters do not allow you to specify the submitted or graded timestamps like the REST API does. You would have to do the filtering on your end. For example, you could make a query like this and pass in the assignmentId in the variables portion of the request.

 

query getSubmissions($assignmentId: ID!) {
  assignment(id: $assignmentId) {
    submissionsConnection {
      nodes {
        submittedAt
        state
        user {
          email
          sisId
          sortableName
        }
      }
    }
  }
}

 

Unless the classes are small, using the REST API and limiting the request based off the submitted_since the last time it ran is likely going to be faster. Unless the classes are large, GraphQL requests will likely not have to mess with pagination. I think you get 1 minute for the request to complete.

The major drawback is that polling the API only works for one assignment at a time, though. You would want to create a list of all your courses and assignment IDs and then poll each one. Make sure that you don't do it so quickly that you run into the throttling constraints. Some languages (Python) are synchronous and you can only make one API call at a time while others (JavaScript) allow you to make multiple calls at the same time. My JavaScript jobs finish a lot faster, but I have to make sure I don't hit the requests too quickly.

I use this approach with our orientation that has thousands of students, but limiting it to those recently submitted doesn't take long. I actually use GraphQL for that one, which doesn't allowing the submitted_since, but we remove the students from that course once they've completed it, so it doesn't take long. GraphQL only returns information for those who have submitted the assignment while the REST API.

If you're trying to guess how often you could poll the data, a ball-park figure I use with my JavaScript code is no more than 10 requests per second. Sometimes it's more or sometimes less depending on the request. That could give you up to 600 courses per minute, but I would slow it down and space it out if you can. Just because you can check 600 courses a minute doesn't mean that you want to sustain that and poll every minute. On the other hand, if you're using Python, it took me 0.7 seconds to request 100 results. That would take over 14 minutes to query those 600 courses, so you obviously cannot query as often.

If you use JavaScript, then you want a throttling library (I use Bottleneck with Node JS). You can control the number of simultaneous requests as well as the delay between them. I've found the delay between them is the more important parameter. If you set it to 100 ms between requests, you're not going to get more than 10 per second. Specifying the submitted_since can help keep the number of requests small. If I request 10 results, it only took 0.4 seconds and I could probably set my delay to 50 ms rather than 100 ms to get 20 courses per second. The warnings about hitting the system too hard still apply. Just because you can doesn't mean you should. I'm just trying to help you get a sense of how much time this might take.

 

A third approach involves using Canvas Live Events. The recommended approach is to set up an AWS SQS Queue, although you then need to act on the information in the queue (I poll the results every five minutes). There is a charge for retrieving information from the queue, but it's pretty small. I'm from a small college and I only get events related to viewing things or submitting assignments. My bill is usually under $1 per month. I put the data into a local database where I can then act on it as needed.

There is a submission_created event. It happens every time an assignment is submitted or resubmitted. It includes information about the submission, including when it happened, the course SIS code, the assignment id, the grade, and the Canvas user_id.

The benefit of this over the other methods is that you get the notification for all of your courses and you don't have to poll each one individually and you can likely get it within 5 minutes of when it happened.

Unfortunately, it does not have the name of the assignment, so you will still need a list of every assignment that this should trigger for. You'll need to look up information about the users to customize your responses, but this might come from a local database. I store the Canvas user IDs locally so that I don't have to make an API query to get the information, but the API request wouldn't take much time. Also, the submission ID is given, so you could use GraphQL to get the information about the submission and user together.

It also sends a notification for all submissions, not just the ones you want. If you're at a large school, this could be a lot and it may take some time to get into the queue. I poll my AWS SQS queue every 5 minutes and get most of the results that are in the queue. I'm using the cheaper version and sometimes it takes up to 15 minutes to work it's way from Canvas to my server.

You can bypass AWS completely and just send the information to your server. I did this at first in testing mode. It went to a PHP script that received the notification and saved it. But it could have just as easily done the processing to send the message. Then I wouldn't have to mess with the SQS queue, it's pricing, and the slight delays.

A potential problem with the live events is that a best effort is made to send them. If the servers are overloaded or the network is congested or there is a network disruption, they don't get through. They are not resent until accepted, they are just sent once. In the grand scheme, I've not had issues enough to worry about it, but if you want to make sure that everyone get the email, then you fall back to the second method as a backup.

 

None of these are instantaneous (except the live events going to your server). The closest you would get if you're doing this for lots of classes is the live events approach. It may take a few minutes before it becomes available in the queue. The polling through the API can take a long time or it can be really quick.

View solution in original post

Who Me Too'd this solution