This is because xDB data is not committed until after the user's session ends.

This link contains a little more information on why that is: https://doc.sitecore.net/sitecore_experience_platform/setting_up__maintaining/xdb/session_state/session_state

> Session state is a way of identifying contacts on your website by assigning them a unique session ID and by using cookies. Every time a contact makes a request, such as triggering a campaign or a goal this information is held in session state until the end of session.
>
>This means that fewer server trips are needed to write data back and forth to the collection database. Instead, xDB makes one trip at the start of a session to identify the contact and a second at the end to save all the session data back to the collection database.

The xDB data is committed in the `postSessionEnd` pipeline if I'm not mistaken. There is also the `sessionEnd` pipeline which handles some analytics stuff among other things and is run before the `postSessionEnd` pipeline (obviously).

<!-- language-all: lang-xml -->

    <sessionEnd>
      <!-- ... -->
      <processor type="Sitecore.Analytics.Pipelines.SessionEnd.InitializeTracker, Sitecore.Analytics" patch:source="Sitecore.Analytics.Tracking.config"/>
      <processor type="Sitecore.Analytics.Pipelines.SessionEnd.RaiseVisitEnd,Sitecore.Analytics" patch:source="Sitecore.Analytics.config"/>
    </sessionEnd>
    <postSessionEnd>
      <processor type="Sitecore.Analytics.Pipelines.PostSessionEnd.CommitSession, Sitecore.Analytics" patch:source="Sitecore.Analytics.Tracking.Database.config"/>
    </postSessionEnd>

I don't know enough about engagement plans to offer any advice on wether or not it is suited for sending notifications immediately.