[rules-users] java.lang.OutOfMemoryError: Java heap space

Wolfgang Laun wolfgang.laun at gmail.com
Fri Oct 12 07:35:40 EDT 2012


Hi,

a nice problem... see below

On 12/10/2012, mohan <mohan.narangoda at gmail.com> wrote:
> Hi laune,
> I'll explain the process briefly. I’m getting voice call events from our
> billing system. We want give some offers if call made inside specific cell
> (uploaded this fact to WM in advance) . But we have to give offer only once
> per day. So repeated calls inside this cell won’t eligible for offer again.
> To achieve this we initiate a new event(NotificationEvent) and insert into
> WM and set metadata @expires(24h) against each mobile no. Ultimately over
> 1000K NotificationEvents are residing in WM per day and guess it will
> trigger OutOfMemory exception.  How to handle such a case? Do we need to use
> caching mechanism?
>

Unclear: Is NotificationEvent in the preceding paragraph the
OfferedEvent in your rule below? And the expiry would have to be set
for OfferedEvent, not "each mobile no" (as written above).

Also, clarify "once per day". It seems that you want "not again in the
next 24 hours but it can also be interpreted as "only once between
0:00 and 24:00". (The latter would be much easier to handle.)

Beware: nothing of the code below is tested.

Reducing the number of facts can be done by registering offers made in a
one fact per offerId (assuming a mobile number can be stored in a long,
which should be possible):

declare OffersMade
  offerId : int
  origin2time : Map<Long,Long>
end

You match a call event to an offer:

rule "Call matches Offer"
when
    $vc : VoiceCallEvent( $ct : eventTime,
                          $cell : cellID,
                          $mobile : originNumber)
    $offer : CymOfferInfo($valTo : validTo.time >= $ct,
                          cellId == $cell,
                          $offerId : offerType.getId,
                          $msgContent : cepMsgTemplates.getId)
then
end

Then there's two cases: you don't have a matching OffersMade yet, or
you have but the caller isn't registered:

rule "No such offer yet"
extends "Call matches Offer"
when
    not OffersMade( offerId == $offerId )
then
    OffersMade offersMade = new OffersMade();
    offersMade.setOfferId( $offerId );
    Map o2t = new HashMap();
    offersMade.setOrigin2Time( o2t );
    o2t.put( $mobile, $ct.getTime() );
    insert( offersMade );
    MdbServiceUtil.sendSMS( $mobile, $msgContent );
    retract( $vc );
end

rule "No offer for this origin"
extends "Call matches Offer"
when
    $om: OffersMade( offerId == $offerId,
                     origin2time.keySet not contains $mobile )
then
    $om.getOrigin2Time().put( $mobile, $ct.getTime() );
    update( $om );
    MdbServiceUtil.sendSMS( $mobile, $msgContent );
    retract( $vc );
end

Finally you need to get rid of old entries. This can be done in a rule
with a timer:

rule "erase old offers"
timer (cron:* 0/15 * * * ?)
when
    $om: OffersMade()
then
    boolean change = false;
    long limit = (new Date()).getTime() - 24*60*60*1000;
    for( Map.Entry entry: $om.getOrigin2Time().entrySet() ){
        if( (Long)entry.getValue() <= limit ){
           $om.getOrigin2Time().remove( entry.getKey() );
           change = true;
        }
    }
    if( change ) update( $om );
end

This still requires two Long objects per offer made (and overhead for the Map).

You might reduce this further by storing the time only once per
OffersMade, so that it is sufficient to have a Set for the
originNumbers:

declare OffersMade
  offerId : int
  offerTime : long
  origins : Set<Long>
end

Of course it would be obtuse to have one OffersMade per millisecond,
which means that offerTime must be reduced to ticks of some reasonable
granularity, I'd say between 1m and 1h. The required rule set is
similar to the preceding one, even simpler, as it is, for instance,
possible to discard an OffersMade object entirely after 24 hours:

rule "discard old set"
timer( int: 24h )
when
    $om: OffersMade
then
    retract( $om );
end

-W



> Thanks.
>
> see below code snippet
>
> rule "Voice CYM offer selector"
> dialect "java"
> no-loop true
> when
>         $vc : VoiceCallEvent( $ct : eventTime, $cell : cellID, $mobile :
> originNumber) from entry-point "IN-VOICE-CALL-EVENT"
>         $offer : CymOfferInfo($valTo : validTo.time >= $ct, cellId ==
> $cell,$offerId : offerType.getId, $msgContent : cepMsgTemplates.getId)
>         not( OfferedEvent(mobileNo == $mobile , offerId ==  $offerId ))
> then
>        CYMOfferMessage genMsg = new CYMOfferMessage();
>        OfferedEvent offered = new OfferedEvent();
>        offered.setMobileNo($mobile);
>        offered.setOfferId((String)$offerId);
>        genMsg.setMobile($mobile);
>        genMsg.setMsgContent($msgContent);
>
>     /* atttach offer here */
>
>     /*  drop SMS message to queue & block offer trigger again*/
>         mdbService.dropMessage(genMsg);
>         insert(offered);
> end
>
>
>
> --
> View this message in context:
> http://drools.46999.n3.nabble.com/java-lang-OutOfMemoryError-Java-heap-space-tp4020185p4020235.html
> Sent from the Drools: User forum mailing list archive at Nabble.com.
>
> _______________________________________________
> rules-users mailing list
> rules-users at lists.jboss.org
> https://lists.jboss.org/mailman/listinfo/rules-users
>



More information about the rules-users mailing list