Announcement

Collapse
No announcement yet.

Is it possible to debug custom scheduled task?

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • Beefy Nugget
    replied
    Just a small update, there is a built in log system for the scheduled tasks. I found it being used inside the templateorderemails.mv inside the merchant-9.006 source. Unfortunately i don't seem to have access to "g.Module_Feature_SCH_DB" to see what the parameters do exactly. But from my best guess it looks like "[ g.Module_Feature_SCH_DB ].ScheduledTaskLog_Insert( Current Task id, Log type, Message )" I am guessing that 'E' is the log type and 'E' stands for error. The other values i have seen passed inside this parameter are 'I' and only display informative text.

    -Function call inside templateorderemails.mv-
    <MvASSIGN NAME = "l.null" VALUE = "{ [ g.Module_Feature_SCH_DB ].ScheduledTaskLog_Insert( l.task:id, 'E', 'Unable to send notification for card ending in \'' $ l.paymentcard:lastfour $ '\' for customer \'' $ l.paymentcard:customer:login $ '\': ' $ g.Error_Message ) }">

    To help anyone looking for the same answer here is a simple example.

    Code:
    <MvCOMMENT>
                |
                | Required function from using "scheduledtask" feature.  We will use this to parse the task operation to determine what function to call
                | The function we call will then be passed l.task
                |
     </MvCOMMENT>
    <MvFUNCTION NAME = "ScheduledTaskModule_Execute" PARAMETERS = "module var, task var" STANDARDOUTPUTLEVEL = "">
    
        <MvIF EXPR = "{ l.task:operation EQ 'myTask1' }">
            <MvFUNCTIONRETURN VALUE = "{ MyTask1Function(l.task) }">
        </MvIF>
    
        <MvIF EXPR = "{ l.task:operation EQ 'myTask2' }">
            <MvFUNCTIONRETURN VALUE = "{ MyTask2Function(l.task) }">
        </MvIF>
    
        <MvFUNCTIONRETURN VALUE = "{ [ g.Module_Library_Utilities ].Error( 'MER-BLA-00002', 'Unsupported operation' ) }">
    </MvFUNCTION>
    
    
    <MvCOMMENT>
                |
                | Custom Function that will be called and throw an error message inside the task log
                |
     </MvCOMMENT>
    <MvFUNCTION NAME = "MyTask1Function" PARAMETERS = " task var" STANDARDOUTPUTLEVEL = "">
    
    <MvASSIGN NAME = "l.null"     VALUE = "{ [ g.Module_Feature_SCH_DB ].ScheduledTaskLog_Insert( l.task:id, 'E', 'OH NOOOO WE MADE AN ERROR!') }">
    
        <MvFUNCTIONRETURN VALUE = 1>
    </MvFUNCTION>
    
    
    <MvCOMMENT>
                |
                | Custom function that will be called and write a message to the task log
                |
     </MvCOMMENT>
    <MvFUNCTION NAME = "MyTask2Function" PARAMETERS = " task var" STANDARDOUTPUTLEVEL = "">
    
    <MvASSIGN NAME = "l.null"     VALUE = "{ [ g.Module_Feature_SCH_DB ].ScheduledTaskLog_Insert( l.task:id, 'I', 'WOO Error free!!!') }">
    
        <MvFUNCTIONRETURN VALUE = 1>
    </MvFUNCTION>
    Last edited by Beefy Nugget; 01-20-18, 12:03 PM. Reason: Some cleanup, also added calling module to top example

    Leave a comment:


  • Beefy Nugget
    replied
    yeah i ended up catching that a little later and fixing it. I actually ended up getting my module all working after your help with finding a way to debug. I plan on posting the source after i get it cleaned up and commented so it may help others in the future :D

    Leave a comment:


  • Kent Multer
    replied
    Yes, I sometimes think of the solution for a problem about ten seconds after I hit the Submit button to ask the forum for help :^.

    I see that one of my earlier points was a little vague. The one place where you can have a variable name with two dots in it is a database field reference. So for example, where you wrote members.d:id, the correct form is members.d.id. The "d" is a prefix letter, like the "g" at the start of a global variable name. I guess my post was correct if you consider "members.d" to be a long prefix ...

    Leave a comment:


  • lesliekirk
    replied
    Originally posted by Beefy Nugget View Post
    Haha well as luck would have it i ended up fixing the issue as i typed my last post.
    Isn't that how it happens sometimes? I will be in the middle of writing up a post, going back through all the steps I can attempt to write some form of clarity and I see something I missed that ends up fixing my problem. Forum posts can be a form of "troubleshooting with friends"

    Leave a comment:


  • Beefy Nugget
    replied
    Haha well as luck would have it i ended up fixing the issue as i typed my last post. Inside the "Load_Active_BA_List" i forgot to place the function return inside the mvopenview error. I fixed it inside the code posted here because i noticed it was missing, and when i applied the fix to the actual code it started being called.

    Thank you again so much, i dont feel so helpless now lol. Its still not doing what i want but now at least i can try to work it out, such is the life if debugging
    Last edited by Beefy Nugget; 01-17-18, 11:16 AM.

    Leave a comment:


  • Beefy Nugget
    replied
    Hey Kent,

    Thank you so much for responding. Also sorry for taking so long to respond back, this is our busy season so its hard to break free right now. I still did not get my module up and running properly however i have taken your advice and used MvExport for a debug system. I am able to see more of whats going on and am grateful for the advice :D. I have a "g.debug" that i am using to add my debug logs into then at the end of the function calling "<MvEXPORT FILE = " MDC_NewScanDebug.txt " DELIMITER = "{ l.null }" FIELDS = "g.debug">" Im using global instead of local because im adding text to the log in other functions. The thing that is currently puzzling me is that one of my helper functions appears to not be getting called. My function "Load_Member_List" is being called and adds to the debug log just fine however "Load_Active_BA_List" does not. I also changed my variables to not include "Club." and instead just use "l.BusinessAccounts" or "l.BusinessAccounts:id" :D

    Code:
    <MvFUNCTION NAME = "Load_Member_List" PARAMETERS = "ClubList var" STANDARDOUTPUTLEVEL = "">
    
        <MvASSIGN NAME = "g.debug" VALUE = "{g.debug $'
        Load Member List Called' $ asciichar(9)}">
    
        <MvASSIGN NAME="l.sql" VALUE="{ 'SELECT * FROM' $ g.Store_Table_Prefix $ 'ClubMemberList' }">
    
        <MvOPENVIEW NAME="Merchant" VIEW="members" QUERY = "{ l.sql }">
        <MvIF EXPR = "{ g.MvOPENVIEW_Error }">
                <MvFUNCTIONRETURN VALUE = "{  'Select Error: ' $ g.MvOPENVIEW_Error  }">
        </MvIF>
    
        <MvASSIGN NAME="l.posn" VALUE="{ 1 }">
        <MvWHILE EXPR="{ NOT members.d.eof }">
    
            <MvCOMMENT> Loop through each record and copy to an array.</MvCOMMENT>          
            <MvASSIGN NAME="l.ClubList" INDEX="{ l.posn }" MEMBER="id"  VALUE="{ members.d:id }">
            <MvASSIGN NAME="l.ClubList" INDEX="{ l.posn }" MEMBER="user_id"  VALUE="{ members.d:user_id }">
            <MvASSIGN NAME="l.ClubList" INDEX="{ l.posn }" MEMBER="date_added"  VALUE="{ members.d:date_added }">
    
    
            <MvSKIP NAME="Merchant" VIEW="members" ROWS="1">
            <MvASSIGN NAME="l.posn" VALUE="{ l.posn + 1 }">
        </MvWHILE>
    
        <MvFUNCTIONRETURN VALUE = "{  ( l.posn - 1 ) }">
    
    </MvFUNCTION>
    
    <MvFUNCTION NAME = "Load_Active_BA_List" PARAMETERS = "baList var" STANDARDOUTPUTLEVEL = "">
    
    
    
        <MvASSIGN NAME = "g.debug" VALUE = "{g.debug $ ' Loading Active BA List' $ asciichar(9)}">
    
    
        <MvCOMMENT> Gets the ID Value of 'Magic Darts Club' business account (NOTE: This is incase the id changes, the name should never changed </MvCOMMENT>
        <MvASSIGN NAME = "l.ClubBusinessAccount" VALUE = "">
        <MvEVAL EXPR = "{ [g.Module_Feature_CUS_DB].BusinessAccount_Load_Title( 'Magic Darts Club', l.ClubBusinessAccount )}">
    
        <MvASSIGN NAME = "g.debug" VALUE = "{g.debug $ '
        Club ID: ' $ l.ClubBusinessAccount:id $ asciichar(9)}">
    
        <MvEXPORT FILE = " MDC_BA_ClubID.txt " 
                  DELIMITER = "{ l.null }" 
                  FIELDS = "g.debug">
    
        <MvASSIGN NAME="l.sql" VALUE="{'SELECT * FROM ' $ g.Store_Table_Prefix $ 'Customers WHERE account_id = ' $ l.ClubBusinessAccount:id}">
    
        <MvOPENVIEW NAME="Merchant" VIEW="accounts" QUERY = "{ l.sql }">
    
        <MvIF EXPR = "{ g.MvOPENVIEW_Error }">
    
                <MvASSIGN NAME = "g.debug" VALUE = "{g.debug $ ' MVSELECT ERROR!' $ g.MvOPENVIEW_Error }">
                <MvFUNCTIONRETURN VALUE = "{  'Select Error: ' $ g.MvOPENVIEW_Error  }">
    
        </MvIF>
    
        <MvASSIGN NAME="l.posn" VALUE="{ 1 }">
        <MvWHILE EXPR="{ NOT accounts.d.eof }">
    
            <MvCOMMENT> Loop through each record and copy to an array.</MvCOMMENT>          
            <MvASSIGN NAME="l.BusinessAccounts" INDEX="{ l.posn }" MEMBER="id"  VALUE="{ members.d:id }">
    
    
            <MvASSIGN NAME = "g.debug" VALUE = "{ g.debug $ '
        Added Member : ' $ members.d:id $ asciichar(9)}">
    
    
    
            <MvSKIP NAME="Merchant" VIEW="accounts" ROWS="1">
            <MvASSIGN NAME="l.posn" VALUE="{ l.posn + 1 }">
        </MvWHILE>
    
        <MvFUNCTIONRETURN VALUE = "{  ( l.posn - 1 ) }">
    
    
    </MvFUNCTION>

    Leave a comment:


  • Kent Multer
    replied
    For starters, "l.Club.BusinessAccounts" is not a valid Miva Script variable name. The dot is only valid after the "l" or other prefix letter. If l.Club is an object with named members, you should use the colon to specify member names, e.g. l.Club:BusinessAccounts. That being said, the VM does accept non-standard characters in some cases, so if you're not getting compiler errors, you may be OK here. But keep in mind that a reference to l.Club will NOT return all the l.Club.xxxxx variables in one object. You need to use colons if you want that behavior.

    As a general technique, scheduled tasks can be hard to debug, since you can't just MvEVAL some messages onto your screen to monitor their activity. But you can use MvEXPORT to write messages into a log file, and then look at it after the task runs to see what's going on.

    HTH --

    Leave a comment:


  • Beefy Nugget
    replied
    Just a small update, i cant find anything about debugging scheduled tasks so i am kinda stuck.

    Leave a comment:


  • Is it possible to debug custom scheduled task?

    *Edit* To save anyone with the same problem a bit of time, i have quoted the two best answers for me. Cheers!

    Answer 1: "....there is a built in log system for the scheduled tasks. I found it being used inside the templateorderemails.mv inside the merchant-9.006 source. Unfortunately i don't seem to have access to "g.Module_Feature_SCH_DB" to see what the parameters do exactly. But from my best guess it looks like "[ g.Module_Feature_SCH_DB ].ScheduledTaskLog_Insert( Current Task id, Log type, Message )" -Beefy Nugget

    Answer 2: "As a general technique, scheduled tasks can be hard to debug, since you can't just MvEVAL some messages onto your screen to monitor their activity. But you can use MvEXPORT to write messages into a log file, and then look at it after the task runs to see what's going on." -Kent Multer


    I am currently writing a module that will track business account activation times and after a year will automatically unassigned the business account from the customer. I decided to go the scheduled task route so i broke the job into two tasks. First task being an 'Update' tracked accounts task that should be ran semi frequently, and a "Remove Expired" task that can be run at the end of each day. I am able to get the module to compile, attach to store, and create a new "TrackedMembers" database. However when i run any of my tasks, nothing happens. The scheduled task log simply says it ran successfully. When i check the "TrackedMembers" database i find that nothing was added (Even though it should have added a few entry's). I have been trying for a few hours to debug what is going on but i cant seem to find any information on debugging, or even debugging a scheduled task.

    Attached is the code, It was all neat and commented until i started getting desperate and trying different things. So please don't mind the mess :P Also any tips on things i am doing wrong or odd would be appreciated. Thank you :D


    Code:
    <MvFUNCTION NAME = "Run_New_Scan" PARAMETERS = " task var" STANDARDOUTPUTLEVEL = "">
    
    
        <MvEVAL EXPR = "{ miva_openlog( 'CLUB_NEW_SCAN-', '', USER )}">
    
    
        <MvIF EXPR = "{ NOT miva_writelog( 'DEBUG', 'This is a DEBUG message' ) }">
    
        </MvIF>
    
        <MvCOMMENT> Sets blank variable to hold the member list
        <MvASSIGN NAME = "l.Club.BusinessAccounts" VALUE = "">
        </MvCOMMENT>
        <MvCOMMENT> Loads list into the 'l.Club.List' Variable </MvCOMMENT>
        <MvEVAL EXPR = "{ Load_Active_BA_List( l.Club.BusinessAccounts )}">
    
        <MvCOMMENT> Sets blank variable to hold the users who are part of the club business acount, then fetches the array from the customer DB
        <MvASSIGN NAME = "l.Club.BusinessAccounts" VALUE = "">
        <MvASSIGN NAME = "l.Club.Offset" VALUE = 0>
        <MvEVAL EXPR = "{ [g.Module_Feature_CUS_DB].CustomerList_Load_Offset( 1, l.Club.ID, 'account_id', 0, l.Club.Offset, l.Club.BusinessAccounts  )}">
    
        </MvCOMMENT>
    
        <MvCOMMENT> Sets blank variable to hold the member list </MvCOMMENT>
        <MvASSIGN NAME = "l.Club.List" VALUE = "">
        <MvCOMMENT> Loads list into the 'l.Club.List' Variable </MvCOMMENT>
        <MvEVAL EXPR = "{ Load_Member_List( l.Club.List )}">
    
    
    
        <MvCOMMENT> Loop thru all accounts with club member business account, and check if the tracked list contains each one </MvCOMMENT>
        <MvFOREACH ITERATOR = "l.item" ARRAY = "l.Club.BusinessAccounts" INDEX = "l.pos">    
    
            <MvCOMMENT> Checks to see if the account is already being tracked </MvCOMMENT>
            <MvIF EXPR = "{ miva_array_search( l.Club.List, 0, l.element, 'l.element:user_id EQ ' $ l.item:id ) }">
                <MvCOMMENT> Account already being tracked, do nothing  (TODO: could change to 'EXPR = NOT' and avoid the extra <MvELSE>) </MvCOMMENT>
            <MvELSE>
                <MvCOMMENT> Business account not found in stored list.  Must now add it to list with date </MvCOMMENT>
                <MvEVAL EXPR = "{ ClubList_Insert( l.item) }">
    
            </MvIF>
    
        </MvFOREACH>
    
        <MvEVAL EXPR = "{ miva_closelog() }">
    
    
        <MvFUNCTIONRETURN VALUE = 1>
    </MvFUNCTION>
    
    <MvFUNCTION NAME = "Run_Expired_Scan" PARAMETERS = " task var" STANDARDOUTPUTLEVEL = "">
    
        <MvCOMMENT> Sets blank variable to hold the member list </MvCOMMENT>
        <MvASSIGN NAME = "l.Club.List" VALUE = "">
        <MvCOMMENT> Loads list into the 'l.Club.List' Variable </MvCOMMENT>
        <MvEVAL EXPR = "{ Load_Member_List( l.Club.List )}">
    
        <MvCOMMENT> Setting the date variables </MvCOMMENT>
        <MvASSIGN NAME = "l.vyear" VALUE= "{tm_year}">
        <MvASSIGN NAME = "l.vmon" VALUE = "{padl(tm_mon,2,'0')}">
        <MvASSIGN NAME = "l.vday" VALUE = "{padl(tm_mday,2,'0')}">
        <MvASSIGN NAME = "l.Full_Date" VALUE = "{ vyear $ vmon $ vday}">
    
    
        <MvCOMMENT> Loop thru all accounts with club member business account, and check if the tracked list contains each one </MvCOMMENT>
        <MvFOREACH ITERATOR = "l.item" ARRAY = "l.Club.List" INDEX = "l.pos">    
    
    
            <MvCOMMENT> Determing if it has been a year yet. (Format is all numbers, 'YYYYMMDD' so we add '00010000' for one year) </MvCOMMENT>
            <MvCOMMENT>                                          Ex: 1/1/2018    =      20180101               20190101   = 1/1/2019   </MvCOMMENT>
            <MvIF EXPR = "{ (l.item:date_added + 10000) LT l.Full_Date  }">
    
            <MvELSE>
                <MvCOMMENT> Business account not found in stored list.  Must now add it to list with date </MvCOMMENT>
                <MvASSIGN NAME = "l.Club.ExpiredAccount" VALUE = "">
                <MvCOMMENT> Get the customer account with the stored id </MvCOMMENT>
                <MvEVAL EXPR = "{ [g.Module_Feature_CUS_DB].Customer_Load_ID( l.item:user_id, l.Club.ExpiredAccount )}">
                <MvCOMMENT> Remove the club member business account status </MvCOMMENT>
                <MvASSIGN NAME = "l.Club.ExpiredAccount:account_id" VALUE = 0 >
                <MvCOMMENT> Send back the changed customer account to update the database </MvCOMMENT>
                <MvEVAL EXPR = "{ [g.Module_Feature_CUS_DB].Customer_Update( l.Club.ExpiredAccount )}">
    
                <MvCOMMENT> Remove expired account from the list </MvCOMMENT>
                <MvEVAL EXPR = "{ ClubList_Remove_By_ID( l.item:id ) }">
    
    
            </MvIF>
    
        </MvFOREACH>
    
        <MvFUNCTIONRETURN VALUE = 1>
    </MvFUNCTION>
    
    
    <MvFUNCTION NAME = "Load_Member_List" PARAMETERS = "ClubList var" STANDARDOUTPUTLEVEL = "">
    
        <MvASSIGN NAME="l.sql" VALUE="{ 'SELECT * FROM' $ g.Store_Table_Prefix $ 'ClubMemberList' }">
    
        <MvOPENVIEW NAME="Merchant" VIEW="members" QUERY = "{ l.sql }">
        <MvIF EXPR = "{ g.MvOPENVIEW_Error }">
                <MvFUNCTIONRETURN VALUE = "{  'Select Error: ' $ g.MvOPENVIEW_Error  }">
        </MvIF>
    
        <MvASSIGN NAME="l.posn" VALUE="{ 1 }">
        <MvWHILE EXPR="{ NOT members.d.eof }">
    
            <MvCOMMENT> Loop through each record and copy to an array.</MvCOMMENT>          
            <MvASSIGN NAME="l.ClubList" INDEX="{ l.posn }" MEMBER="id"  VALUE="{ members.d.id }">
            <MvASSIGN NAME="l.ClubList" INDEX="{ l.posn }" MEMBER="user_id"  VALUE="{ members.d.user_id }">
            <MvASSIGN NAME="l.ClubList" INDEX="{ l.posn }" MEMBER="date_added"  VALUE="{ members.d.date_added }">
    
    
            <MvSKIP NAME="Merchant" VIEW="members" ROWS="1">
            <MvASSIGN NAME="l.posn" VALUE="{ l.posn + 1 }">
        </MvWHILE>
    
        <MvFUNCTIONRETURN VALUE = "{  ( l.posn - 1 ) }">
    
    </MvFUNCTION>
    
    <MvFUNCTION NAME = "Load_Active_BA_List" PARAMETERS = "baList var" STANDARDOUTPUTLEVEL = "">
    
        <MvCOMMENT> Gets the ID Value of 'Magic Darts Club' business account (NOTE: This is incase the id changes, the name should never changed </MvCOMMENT>
        <MvASSIGN NAME = "l.Club:ID" VALUE = "">
        <MvEVAL EXPR = "{ [g.Module_Feature_CUS_DB].BusinessAccount_Load_Title( 'Magic Darts Club', l.Club:ID )}">
    
        <MvOPENVIEW NAME="Merchant" VIEW="accounts" QUERY = "{'SELECT * FROM ' $ g.Store_Table_Prefix $ 'Customers WHERE account_id = ' $ l.Club:ID}">
    
        <MvIF EXPR = "{ g.MvOPENVIEW_Error }">
                <MvFUNCTIONRETURN VALUE = "{  'Select Error: ' $ g.MvOPENVIEW_Error  }">
        </MvIF>
    
        <MvASSIGN NAME="l.posn" VALUE="{ 1 }">
        <MvWHILE EXPR="{ NOT accounts.d.eof }">
    
            <MvCOMMENT> Loop through each record and copy to an array.</MvCOMMENT>          
            <MvASSIGN NAME="l.baList" INDEX="{ l.posn }" MEMBER="id"  VALUE="{ members.d.id }">
    
    
            <MvSKIP NAME="Merchant" VIEW="accounts" ROWS="1">
            <MvASSIGN NAME="l.posn" VALUE="{ l.posn + 1 }">
        </MvWHILE>
    
        <MvFUNCTIONRETURN VALUE = "{  ( l.posn - 1 ) }">
    
    </MvFUNCTION>
    
    <MvCOMMENT>
    -
    -    Inserts a new club Member into the 'ClubMemberList'.  Requires a 'ClubMember' to be sent
    -
    </MvCOMMENT>
    <MvFUNCTION NAME = "ClubList_Insert" PARAMETERS = "clubMember" STANDARDOUTPUTLEVEL = "" ERROROUTPUTLEVEL = "">
    
        <MvCOMMENT> Setting the date variables </MvCOMMENT>
        <MvASSIGN NAME = "l.vyear" VALUE= "{tm_year}">
        <MvASSIGN NAME = "l.vmon" VALUE = "{padl(tm_mon,2,'0')}">
        <MvASSIGN NAME = "l.vday" VALUE = "{padl(tm_mday,2,'0')}">
        <MvASSIGN NAME = "l.Full_Date" VALUE = "{ vyear $ vmon $ vday}">
    
        <MvASSIGN NAME = "l.clubMember:id"                VALUE = "{ [ g.Module_Library_DB ].StoreKey_Generate( 'ClubMemberList' ) }">
        <MvQUERY NAME    = "Merchant"
                 QUERY    = "{ 'INSERT INTO ' $ g.Store_Table_Prefix $ 'ClubMemberList
                              ( id, user_id, l.Full_Date )
                              VALUES
                              ( ?, ?, ? )' }"
                 FIELDS    = "l.clubMember:id, l.clubMember:user_id, l.date">
        <MvIF EXPR = "{ g.MvQUERY_Error }">
            <MvFUNCTIONRETURN VALUE = "{ [ g.Module_Library_Utilities ].Error( 'MER-MDC-STS-00003', g.MvQUERY_Error ) }">
        </MvIF>
    
        <MvFUNCTIONRETURN VALUE = 1>
    </MvFUNCTION>
    
    
    <MvCOMMENT>
    -
    -    Removes a Club Member from the 'ClubMemberList'.  Requires an 'id' ( 'ClubMemberList:id', not 'Customer:account_id')
    -
    </MvCOMMENT>
    <MvFUNCTION NAME = "ClubList_Remove_By_ID" PARAMETERS = "id" STANDARDOUTPUTLEVEL = "" ERROROUTPUTLEVEL = "">
    
        <MvQUERY NAME    = "Merchant"
                 QUERY    = "{ 'DELETE FROM ' $ g.Store_Table_Prefix $ 'ClubMemberList WHERE id = ?' }"
                 FIELDS    = "l.id">
        <MvIF EXPR = "{ g.MvQUERY_Error }">
            <MvFUNCTIONRETURN VALUE = "{ [ g.Module_Library_Utilities ].Error( 'MER-MDC-STS-00004', g.MvQUERY_Error ) }">
        </MvIF>
    
        <MvFUNCTIONRETURN VALUE = 1>
    </MvFUNCTION>
    Last edited by Beefy Nugget; 01-20-18, 12:05 PM. Reason: making some text green that i missed
Working...
X