cancel
Showing results for 
Search instead for 
Did you mean: 
cancel
Showing results for 
Search instead for 
Did you mean: 

Community Tip - Learn all about PTC Community Badges. Engage with PTC and see how many you can earn! X

How to remove Remote Things

miikkae
1-Newbie

How to remove Remote Things

How can I remove Remote Things that are show in Monitoring -> Remote Things?

I've been working on a service to automatically create new things based on Resources["DeviceFunctions"].GetUnboundRemoteThings() and binding them too.

Now I have a huge amount of remote things showing in the Remote Things' Monitoring page's "All" tab (with red mark, so they are all offline). There're no actual Things for them to delete, though. That's why it's odd that they don't appear on the "Unbound" tab.

There're no identifiers specified, so when I connect and bind those names with SDK agent, they seem like online, otherwise offline.

If I try to create a Thing with that name, I get an error saying: save failed, status: "Conflict", message: "Object With This Name Already Exists"

even though I can't find Thing with that name.

It seems to have been my bad for not having the the things unbound after closing the SDK agent. Then I just deleted those things and it got somewhat messed up.

1 ACCEPTED SOLUTION

Accepted Solutions
paic
1-Newbie
(To:miikkae)

Most likely these have become 'ghost' entities because they were incorrectly created.

Try restarting Tomcat.

View solution in original post

12 REPLIES 12
paic
1-Newbie
(To:miikkae)

Most likely these have become 'ghost' entities because they were incorrectly created.

Try restarting Tomcat.

miikkae
1-Newbie
(To:paic)

Thanks! Got finally in touch with the guy on the server side and he did the restart.

Ghosts are gone now

AdamR
12-Amethyst
(To:miikkae)

Also note when creating entities via service it is important to include proper error handling in the script.  See the following article....

https://support.ptc.com/appserver/cs/view/solution.jsp?n=CS198580&lang=en_US

miikkae
1-Newbie
(To:AdamR)

Thanks but it seems, we don't have PTC Global Support agreement so I have no access to that article. Some error handling's already included to my service script. I'll ask if we can get that agreement.

AdamR
12-Amethyst
(To:miikkae)

  • To remove existing "ghost" entities, restart Tomcat
  • Proper error handling when creating entities programmatically will mitigate the risk of database corruption and ghost entities
    • Use Try Catch statements to delete entities if they are not created properly
    • Create, Enable and restart the Thing in the try Statement
      • E.g.

try {

     var params = { tags: undefined /* TAGS */,

                         thingTemplateName: "GenericThing" /*THINGTEMPLATENAME */,

                          description: "new thing" /* STRING */,

                          name: thing1 /* STRING */ };

     // no return

     Resources["EntityServices"].CreateThing(params);

     Things[thing1].EnableThing();

     Things[thing1].RestartThing();

}

  • ​​If there is any error in Thing creation, use the catch statement to delete the entities
    • E.g.

catch(e) {

     logger.error("Unable to create Thing");

      var params = { name: thing1 /* THINGNAME */ };

      // no return

     Resources["EntityServices"].DeleteThing(params);

}

miikkae
1-Newbie
(To:AdamR)

Thanks!

I actually did have the try catch statement there but was missing DeleteThing method from catch side.

qngo
5-Regular Member
(To:AdamR)

There's a problem with DeleteThing in catch block. If the Thing exists really, this catch will delete the real Thing and not the ghost one.

Is is possible to distinguish between a real Thing and a ghost one ?

Hi Quang-Dung,

You can't have Ghost and Real Thing with the same name on the same system, or it's a Ghost or it's a real Thing.

If you are asking how to know if a Thing it's a Ghost or a Real Thing, I think there isn't an answer to this.

If you want to prevent to create an already existing thing, try to check first for it's existence.

Don't try to do Try/Catch/Delete to an unconsistent system, first restart your system, then do it on the correct way.

Carles.

qngo
5-Regular Member
(To:CarlesColl)

Hi Carles,

thank you for your answer. Can you please tell me a service to find Thing only by name, without Template etc. ? I tried SearchThings with a query parameter without success. I wonder if I have to use searchExpression parameter instead.

You may do something like Things["ThingName"]==null or Things["ThingName"]==undefined.

Hi Quang-Dung,

In regards to ghost entities, I would also like to share a script with you with which you can detect all ghost things in your system. It doesn't help you delete them, but you could run it in a subscription to get notified when you have any ghost entities and then immediately restart the server. The service receives as an input parameter your server name (HostURL) and an AppKey name (not the actual appKey value). It basically compares the Things in the spot light search (database) with the Things in the REST API (in memory). If there is a difference, it will print that out as an infotable (which will be the result of your service).

In my case the DataShape for the resulting Infotable is one specific to my project, but you can change it to include just the thingName.

Let me know if this helps or if you have any questions.

try { var params = {

    searchExpression: "*" /* STRING */,

    types: {"items":["Thing"]}

    /* JSON */,

    withPermissions: true /* BOOLEAN */,

    aspects: {"isSystemObject":false}

    /* JSON */,

    searchDescriptions: true /* BOOLEAN */,

    sortBy: "lastModifiedDate" /* STRING */,

    isAscending: false /* BOOLEAN */,

};

// result: INFOTABLE dataShape: SpotlightSearch

/* controllers in spotlight search may contain entities

   that have been created only in memory

*/

var spotlightSearchItems = Resources["SearchFunctions"].SpotlightSearch(params);

/* the infotable below will contain ONLY things

   that are also in the ThingWorx database

*/

// result: INFOTABLE dataShape: RootEntityList

// result: STRING

var KeyID = ApplicationKeys[AppKey].GetKeyID();

var params = {

  proxyScheme: undefined /* STRING */,

  headers: undefined /* JSON */,

  ignoreSSLErrors: undefined /* BOOLEAN */,

  useNTLM: undefined /* BOOLEAN */,

  workstation: undefined /* STRING */,

  useProxy: undefined /* BOOLEAN */,

  withCookies: undefined /* BOOLEAN */,

  proxyHost: undefined /* STRING */,

  url: HostURL + "/Thingworx/Things?appKey=" + KeyID/* STRING */,

  timeout: undefined /* NUMBER */,

  proxyPort: undefined /* INTEGER */,

  password: undefined /* STRING */,

  domain: undefined /* STRING */,

  username: undefined /* STRING */

};

// result: JSON

//var controllers = Resources["ContentLoaderFunctions"].LoadJSON(params);

var entities = Resources["ContentLoaderFunctions"].LoadJSON(params);

var params = {

  infoTableName : "InfoTable",

  dataShapeName : "ControllersDisplayShape"

};

// CreateInfoTableFromDataShape(infoTableName:STRING("InfoTable"), dataShapeName:STRING):INFOTABLE(ControllersDisplayShape)

var thingsInfotable = Resources["InfoTableFunctions"].CreateInfoTableFromDataShape(params);

for (var i = 0; i <  entities.rows.length; i++) {

     if (entities.rows.isSystemObject == false)

     thingsInfotable.AddRow({

         ControllerName:entities.rows.name,

         ControllerDisplayName:entities.rows.description

     });

}

var ghostsCount = thingsInfotable.getRowCount()- spotlightSearchItems.getRowCount();

logger.info("Number of ghosts is " + ghostsCount); 

// If the ghost count is zero, the result will just be an empty infotable

var params = {

    infoTableName : "InfoTable",

    dataShapeName : "ControllersDisplayShape"

};

// CreateInfoTableFromDataShape(infoTableName:STRING("InfoTable"), dataShapeName:STRING):INFOTABLE(DisplayNameDataShape)

var result = Resources["InfoTableFunctions"].CreateInfoTableFromDataShape(params);

// if the ghostCount is higher than 0, we want to check which is(are) the actual ghost controller(s)

if (ghostsCount > 0) {

    for (var i = 0; i < thingsInfotable.getRowCount(); i++) {

        for (var j = 0 ; j < spotlightSearchItems.getRowCount(); j++) {

            if (thingsInfotable.rows.ControllerName == spotlightSearchItems.rows.name) {

                //we discard from the spotlight search every controller which we already found in the DB

                //to reduce our search time

                thingsInfotable.RemoveRow(i);

                i--;

                break;

            }

        }

    }

   

    // the remaining infotable will contain only the ghosts

  var result = thingsInfotable;

}

    } catch (err) {

        logger.error ("Encountered error " + err + " at line " + err.lineNumber) ;

    }

qngo
5-Regular Member
(To:costinb)

Thank you! The concept works perfectly for me. Also, I learnt some new useful services like RemoveRow which are not listed in the InfoTableFunctions' services.

Top Tags